Ciągiem nazywamy funkcję, której dziedziną jest zbiór liczb naturalnych lub jego skończony odcinek początkowy . Ciągiem liczbowym nazywamy ciąg, którego wyrazy są liczbami.
Liczbę nazywamy granicą ciągu nieskończonego , jeśli dla każdej liczby dodatniej istnieje taka liczba , że dla zachodzi nierówność:
Ciągiem zbieżnym (rozbieżnym) nazywamy ciąg, który posiada granicę (nie posiada granicy).
Jeśli ciąg posiada granicę to tylko jedną.
Każdy ciąg zbieżny jest ograniczony.
Przy założeniu, że ciągi i są zbieżne, zachodzą następujące wzory:
- (dla iloczynu i ilorazu też zachodzi)
Jeżeli ciąg jest zbieżny i , to .
Jeżeli ciąg jest zbieżny, to .
(Tw. o trzech ciągach): Jeśli , to ciąg jest zbieżny, przy czym .
Zmiana skończonej ilości wyrazów ciągu nie wpływa na jego zbieżność/granicę.
Podciąg ciągu zbieżnego jest zbieżny do tej samej granicy, co ciąg dany.
Po ludzku: Ciągi Cauchy'ego to takie ciągi, dla których odległości między wyrazami zmierzają do zera. Oznacza to, że wybierając dowolnie małą dodatnią liczbę rzeczywistą , można ustalić odpowiednio duży wskaźnik taki, że dowolne dwa wyrazy o wyższych wskaźnikach są odległe od siebie o mniej niż .
Ciąg jest zbieżny gdy jest ciągiem Cauchy’ego. (ale niekoniecznie odwrotnie).
Każdy ciąg Cauchy’ego jest ograniczony.
Macierzą (rzeczywistą) wymiaru m$\times$n, gdzie m, n , nazywamy prostokątną tablicę złożoną z m$\times$n liczb rzeczywistych ustawionych w m wierszach i n kolumnach
Suma/różnica
Niech macierz , . Sumą/różnicą nazywamy macierz , której elementy określone są wzorami
Zatem,
Iloczyn macierzy przez liczbę
Niech niech będzie dowolną liczbą rzeczywistą. Iloczynem macierzy przez liczbę nazywamy macierz której elementy określone są następująco:
dla {}, {}. Piszemy wtedy
Zatem
Iloczyn macierzy
Iloczyn macierzy jest możliwy jeśli macierz ma tyle samo kolumn co macierz ma wierszy. Iloczynem macierzy przez macierz nazywamy macierz taką, że:
Własności iloczynu macierzy:
Macierz transponowana
Niech
Wówczas
Rząd macierzy
Chcąc obliczyć rząd macierzy musimy znależć największą macierz, której wyznacznik jest różny od zera, wielkość tej niezerowej macierzy będzie szukaną wartością, czyli jeśli największą macierzą, której wyznacznik jest różny od zera jest macierz to rząd macierzy jest równy .
Przyklad
Aby obliczyć rząd macierzy zaczynamy od obliczenia wyznacznika największej macierzy czyli w tym przypadku
Następnie obliczamy macierze do momentu aż wyjdzie nam liczba różna od zera. Z macierzy można utowrzyć 16 macierzy w następujący sposób:
Jeżeli któraś z nich wyjdzie różna od zera to koniec obliczeń. Wystarczy że obliczając wyznacznik macierzy pierwszej wyjdzie nam liczba różna od zera - wtedy z automatu możemy powiedzieć, że rząd macierzy wynosi . Analogicznie jeżeli wszystkie wzory wyjdą na , to wtedy szukamy macierzy poprzez wykreślenie wiersza i kolumny analogicznie jak do kroków powyżej tak aby otrzymać macierz (czyli wykreślając po dwa wiersze i dwie kolumny).
Dla macierzy
operacja ta wygalda nastepująco:
Wyznacznik macierzy
np. Metoda Sarrusa
np. Rozwinięcie Laplace'a
Szukamy w macierzy wiersza lub kolumny która ma najwięcej zer (dla łatwiejszego obliczania). Na przykład:
Dla macierzy
Sytuacja wyglada tak:
Gdzie po równaniu pierwsza liczba to liczba wiersza i kolumny pomnożone przez do potegi razy macierz po wykreśleniu wiersza i kolumny . Następne dodajemy analogicznie.
Maceirz odwrotna $(A^{-1})$
Wzór:
gdzie:
Nie można obliczyć macierzy odwrotnej z macierzy osobliwej, czyli takiej której wyznacznik jest równy . Więc jeśli liczymy macierz odwrotną zawsze zaczynamy od obliczania wyznacznika macierzy, jeśli wyjdzie on to znaczy, że z danej macierzy nie można obliczyć macierzy odwrotnej.
Macierz odwrotna jest określona tylko dla macierzy kwadratowych, których wyznacznik jest .
Macierz odwrotna do macierzy kwadratowej to macierz spełniająca równanie , gdzie to macierz jednostkowa.
Jeśli macierz istnieje to macierz nazwyamy odwracalną, a jeśli macierz nie istnieje to macierz nazywamy nieodwracalną.
Jeśli macierz jest odwracalna to istnieje tylko jedna macierz odwrotna
Własności macierzy odwrotnej
Macierz nieosobliwa - macierz kwadratowa o wyznaczniku róznym od zera
Macierz symetryczna - macierz kwadratowa której wyrazy położone symetrycznie względem przekątnej głównej są równe, przykład:
Proces obliczania macierzy odwrotnej dla macierzy $3\times 3$
Podobnie jak wcześniej najpierw obliczamy wyznacznik macierzy :
Następnie obliczamy macierz dopełnień algebraicznych:
czyli
Więc:
Następnie obliczamy macierz transponowaną:
więc macierz odwrotna będzie miała postać:
Ślad macierzy
Ślad macierzy jest to suma elementów leżących na przekątnej danej macierzy. Ślad macierzy definujemy tylko dla macierzy kwadratowej. Ślad macierzy kwadratowej stopnia jest sumą elementów leżących na głównej przekątnej (diagonali). Ślad macierzy oznaczamy lub .
Mając macierz
obliczamy ślad macierzy w następujący sposób:
Własności śladu macierzy
Rozważmy układ równań liniowych o niewiadomych :
oraz macierz :
nazywać będziemy macierzą układu .
Macierz
nazywać będziemy macierzą wynikową.
Macierz
nazywać będzimy macierzą rozszerzoną układu .
Rozwiązaniem układu nazywać będziemy każdy -elementowy ciąg taki, że po podstawieniu do układu otrzymujemy równości:
Operacje elementarne
Za pomocą operacji elementarnych możemy przekształcać wiersze macierzy.
Możliwe operacje elementarne:
Metoda eliminacji Gaussa
Metoda eliminacji Gaussa polega na stosowaniu operacji elementarnych do macierzy rozszerzonej uładu równań liniowych tak, aby doprowadzić macierz rozszerzoną do postaci schodkowej.
Postać schodkowa:
Przykład:
Twierdzenie Cramera
Rozważamy układ równań liniowych o niewiadomych :
Jeżeli wyznacznik macierzy tego układu jest różny od zero to ten układ ma dokładnie jedno rozwiązanie postaci:
Natomiast macierz powstaje z macierzy poprzez zastąpienie -tej kolumny macierzy przez kolumnę macierzy wynikowej.
Przykład
Najpierw sprawdźmy czy wyznacznik macierzy układu jest rózny od zera
Oznacza to e układ ten ma dokladnie jedno rozwiązanie.
Musimy znalezc wzynacznik odpowiadajace kolejnym niewiadomym, czyli .
$A_1$
Wykreslamy pierwsza kolumne macierzy
W wolne miejsce wpisujemy kolumne macierzy wynikowej
Obliczamy wartosc
Teraz mozemy wyznaczyc niewiadoma
$A_2$
$A_3$
Podsumowujac otrzymalismy nastepujace rzowiazanie ukldau rownan:
Wniosek z twierdzenia Cramera
Prawem rachunku zdan lub tautologia nazywamy wyrażenie zbudowane ze zdań prostych i spójników, które zawsze jest zdaniem prawdziwym (niezależnie od wartości logicznych zdań prostych).
TAUTOLOGIA
W logice wartość logiczną zdania definiujemy jako 0, gdy zdanie to jest
fałszywe, zaś jako 1 , gdy zdanie to jest prawdziwe.
Symbolu 0 używamy również do oznaczenia dowolnego zdania fałszywego,
zaś symbolu 1 do oznaczenia dowolnego zdania prawdziwego.
Koniunkcja - to dwa zdania połączone spójnikiem logicznym .
Koniunkcja dwóch zdań jest prawdziwa jedynie wtedy, gdy oba zdania oraz są prawdziwe.
Alternatywa - to dwa zdania połączone spójnikiem logicznym .
Alternatywa dwóch zdań jest prawdziwa wtedy, gdy przynajmniej jedno ze zdań lub jest prawdziwe.
Implikacja - możemy odczytywać na wiele równoważnych sposobów:
Rownowaznosc - możemy odczytywać na wiele równoważnych sposobów:
Negacja - oznacza jednoargumentowy spójnik negacji, oznacza zdanie:
Najwazniejsze tautologie
Tautologia (z greki) - to wyrażenie, zdanie logiczne, które zawsze jest logiczne
Indukcja matematyczna – metoda dowodzenia twierdzeń o prawdziwości nieskończonej liczby stwierdzeń oraz definiowania rekurencyjnego. W najbardziej typowych przypadkach dotyczą one liczb naturalnych.
Aksjomat indukcji matematycznej
Jeśli jest podzbiorem , ktory spelnia:
to stanowi calosc , tzn .
Innymi slowy oznacza to ze jezeli dowiedziemy ze dany zbior posiada takie same wlasciwosci jak zbior (tj. jest dyskretny, posiada poczatkowy element oraz odlegosc miedzy nasepnymi dyskretnymi elementami jest zawsze taka sama) to element ten jest podzbiorem ale np przesunietym i powiekszonym o jakis skalar.
Przyklady

Permutacja zbioru -elementowego - to dowolny -wyrazowy ciąg utworzony ze wszystkich elementów tego zbioru.
Liczbę permutacji zbioru -elementowego możemy obliczyć ze wzoru:
Przyklady
Kombinacja pozwala policzyć na ile sposobów można wybrać elementów z -elementowego zbioru.
Wzór na kombinację jest następujący:
Kombinację zapisujemy krótko za pomocą Symbolu Newtona:
Przyklady
Przyjmijmy, że mamy dany zbiór elementów (np. zbiór liter). Wariacja z powtórzeniami pozwala na utworzenie ciągu z elementów tego zbioru, z tym, że dopuszcza powtarzanie elementów.
Wzór na wariację z powtórzeniami jest następujący:
Przyklady
Przykładami taki słów są: .
Na każde z miejsc możemy wybrać jedną z liter, zatem wszystkich możliwości mamy:
Przykładami taki słów są: .
Na każde z miejsc możemy wybrać jedną z liter, zatem wszystkich możliwości mamy:
Przyjmijmy, że mamy dany zbiór elementów (np. zbiór liter). Wariacja bez powtórzeń pozwala na utworzenie ciągu z elementów tego zbioru, z tym, że nie dopuszcza powtarzania elementów. Wzór na wariację bez powtórzeń jest następujący:
Przyklady
Mamy do dyspozycji cyfr: .
Przykładowymi kodami o różnych cyfrach są: . Wszystkich takich wariacji bez powtórzeń jest:
Definicja
Zakładamy, że przestrzeń zdarzeń elementarnych \OmegaΩ ma skończoną liczbę zdarzeń elementarnych i każde z nich jest jednakowo prawdopodobne. Wtedy prawdopodobieństwo definiujemy następująco:
Dla dowolnego
Kilka wyjaśnień:
Krótko: prawdopodobieństwo uzyskania jakiegoś wyniku to liczba sprzyjających wyników przez liczbę wszystkich możliwych wyników. Zatem chcąc obliczyć prawdopodobieństwo zajścia pewnego zdarzenia:
Własności prawdopodobieństwa
Prawdopodobieństwo dowolnego zdarzenia losowego A jest zawsze liczbą z przedziału ⟨0;1⟩.
Prawdopodobieństwo zdarzenia pewnego jest równe 1.
Prawdopodobieństwo zdarzenia niemożliwego jest równe 0.
Przydatne wzory
Prawdopodobieństwo zdarzenia przeciwnego:
Prawdopodobieństwo sumy zdarzeń
Prawdopodobieństwo warunkowe
Prawdopodobieństwo warunkowe zajścia zdarzenia A pod warunkiem zajścia zdarzenia B liczymy ze wzoru:
Prawdopodobieństwo całkowite
Jeżeli zdarzenia są parami rozłączne oraz mają prawdopodobieństwa dodatnie, które sumują się do jedynki, to dla dowolnego zdarzenia A zachodzi wzór:
Wzór Bayesa
Jeżeli zdarzenia są parami rozłączne oraz mają prawdopodobieństwa dodatnie, które sumują się do jedynki, to dla dowolnego zdarzenia A zachodzi wzór:
Schemat Bernoulliego
W schemacie Bernoulliego prawdopodobieństwo uzyskania k sukcesów w n próbach można obliczyć ze wzoru:
Klasyczny komputer o architekturze podanej przez von Neumana składa się z trzech podstawowych bloków:
Struktura logiczna komputera
Po załadowaniu programu do pamięci komputera może on zostać w dowolnej chwili wywołany przez operatora. W tym celu musi on wydać polecenie rozpoczęcia wykonywania tego programu przez wymuszenie odczytania pierwszego polecenia tego programu. W tym celu należy spowodować, aby procesor wysłał do pamięci odpowiedni adres. Dalsze polecenia są umieszczone w pamięci kolejno, więc będą odczytywane przez procesor automatycznie. Wykonywanie programu polega, więc na pobieraniu z pamięci kolejnych poleceń i odpowiednich dla tych poleceń argumentów. Argumenty rozkazu mogą być:
- w pamięci i wówczas rozkaz musi zawierać adres miejsca w pamięci, gdzie one się znajduje,
- w rejestrach procesora i wówczas rozkaz musi wskazywać adres odpowiedniego rejestru,
- w samym rozkazie i wówczas programista umieszcza je w odpowiednio w kodzie programu.
W czasie wykonywania programu procesor odczytuje kolejne rozkazy, które następnie musi rozpoznać (dekodować). Po zdekodowaniu rozkazu, w zależności od treści tego rozkazu, procesor podejmuje odpowiednią akcję. Akcja ta polega na wykonaniu odpowiedniej operacji. Między innymi, z treści rozkazu, może wynikać konieczność odczytania argumentów dla niego.
Jeżeli argument znajduje się, w pamięci, to dalsza akcja polega na odczytaniu adresu tego argumentu. Jeżeli adres ten programista umieścił w kodzie programu, to odczytane będzie następne słowo(a) z kodu programu stanowiące ten adres. Jeżeli argument znajduje sic, w rejestrze procesora, to rozkaz musi wskazać, w którym z rejestrów procesora znajduje się adres. Po skompletowaniu całej instrukcji procesor wykonuje ją, a dalej pobiera następny rozkaz i cała akcja się powtarza.

(schemat czytamy od gory - strzalka znika z prawej strony i pojawia sei po lewej dolnej stronie)
Na schemacie:
Typowa organizacja procesora to blok rejestrów, blok ALU i dekoder kodu rozkazowego. Najważniejszym układem procesora jest blok arytmetyczno logiczny ALU wykonujący operacje na argumentach z dwóch rejestrów A i B. Cykl pracy procesora rozpoczyna się od wysłania do pamięci adresu rozkazu. Adres ten znajduje się, w rejestrze LR zwanym licznikiem rozkazów.
Odczytywany z pamięci rozkaz zostaje przesłany do rejestru rozkazów RR. Zawartość tego rejestru jest dekodowana i blok ALU zostaje odpowiednio wysterowany do wykonania danej operacji. Zarówno rozkazy procesora jak i argumenty tych rozkazów są przedstawiane w komputerze w postaci słów binarnych, tj. kodowane w zapisie dwójkowym. (dlugosc slowa zawsze jest taka sama i odpowiada bitowosci komputera tj. 8-bitow, 16-bitow, 32-bity itd)

Pamięć jest podzielona na komórki, w których są przechowywane pojedyncze słowa (bajty). Każda komórka ma swój adres i podanie tego adresu na wejście adresowe pamięci umożliwia dostęp do danej komórki, czyli odczyt lub zapis. W zależności od sygnału O (odczyt) / Z (zapis) pamięć jest odczytywana lub zapisywana.
Wielkość takiej pamięci nazywana jest pojemnością pamięci i jest oznaczana przez (liczba pamiętanych słów przez długość słowa). W jednym cyklu pracy takiej pamięci można odczytać lub zapisać tylko słowo 8-bitowe. W przypadku, gdy długość rozkazu lub argumentu jest większa, to jest on zapisywany w dwóch (lub więcej) komórkach pamięci. Cykl instrukcyjny składa się z 4 faz:
- fazy pobrania rozkazu
- dwóch faz pobrania argumentów rozkazu
- fazy zapisu wyniku do pamięci.
Pozycyjny system liczbowy - to system liczbowy ktory opiera sie o pewien skonczony zestaw cyfr tego systemu. Kazda liczba w systemie pozycyjnym zostaje przedstawiona jako ciag cyfr tego systemu gdzie kazda nastepna cyfra na indeksie () gdzie to ilosc cyfr tego systemu, przedstawia wartosc .
Wzor:
Przyklady
Zamiana z na $(10)$
Zamiana z na $(2), (16)$
Zamiana z na $(16)$

Zamiana z na $(2)$

Zastowosawnie systemu dwojkowego
System dwojkowy oznaczany wykorzystywany jest jako glowny podloze wszystkich obliczen komputerow elektronicznych. Zostal wybrany na system pozycyjny komputerow poniewaz moze przedstawiac brak napieca a napiecie na danej sciezce, w danej komorce pamieci lub nosniku danych co sprawia ze jest to system bardzo prosty poniewaz nie wymaga pomiaru poziomu napiecia pradu przeplywajacego przez komponent w celu uzyskania danyhc z tego komponentu.
Zastosowanie systemu szesnastkowego
System szesnastkowy oznaczany wykorzystywany jest jako roziwniecie systeu dowjkowego. Dzieki wiekszej podstawie tego systemu, liczby zapisywane w nim sa bardziej kompaktowe i dzieki temu bardziej czytelne.
Komputerowa reprezentacja liczb calkowitych z przedzialu od do (przedzial zalezy od standardu), gdzie n jest liczba bitów w slowie maszynowym, zapisywanych w kodzie uzupelnien do dwóch. Zakres liczb 16-bitowych w a.s. (komputery PC) miesci sie w przedziale . Przekroczenie zakresu liczb powoduje nadmiar. W arytmetyce stalopozycyjnej sa wykonywane cztery podstawowe dzialania (+, -, * i /), przy czym stosuje sie dzielenie calkowite.
Reprezentacja liczby rzeczywistej zapisanej za pomocą notacji naukowej. Ze względu na wygodę operowania na takich liczbach, przyjmuje się ograniczony zakres na mantysę i cechę – nazwy te mają w matematyce znaczenie podane w artykule podłoga i sufit, a w niniejszym artykule inne, powszechne w informatyce. Powoduje to, że reprezentacja liczby rzeczywistej jest tylko przybliżona, a jedna liczba zmiennoprzecinkowa może reprezentować różne liczby rzeczywiste z pewnego zakresu.
Stalopozycjne (calkowite)

Stalopozycjne (rzeczywiste)

Stalopozycjne (rzeczywiste cd.)

Zmiennopozycyjne
## 11. System operacyjny. Postrzeganie systemu operacyjnego przez warstwę oprogramowania użytkowego.
System operacyjny jest warstwą oprogramowania operującą bezpośrednio na sprzęcie, której celem jest zarządzanie zasobami systemu komputerowego i stworzenie użytkownikowi środowiska łatwiejszego do zrozumienia i wykorzystania.

System operacyjny pośredniczy pomiędzy użytkownikiem a sprzętem, dostarczając wygodnego środowiska do wykonywania programów. Użytkownik końcowy korzysta z programów (aplikacji), na potrzeby których przydzielane są zasoby systemu komputerowego. Przydziałem tym zarządza system operacyjny, dzięki czemu można uzyskać stosunkowo duży stopień niezależności programów od konkretnego sprzętu oraz odpowiedni poziom bezpieczeństwa i sprawności działania.
Nie ma precyzyjnego określenia, które składniki wchodzą w skład systemu operacyjnego jako jego części.

W ogólnym przypadku w strukturze systemu operacyjnego wyróżnia się jądro oraz programy systemowe, które dostarczane są razem z systemem operacyjnym, ale nie stanowią integralnej części jądra. Jądro jest zbiorem modułów, które ukrywają szczegóły sprzętowej realizacji systemu komputerowego, udostępniając pewien zestaw usług, wykorzystywanych między innymi do implementacji programów systemowych.
Z punktu widzenia kontaktu z użytkownikiem istotny jest interpreter poleceń, który może być częścią jądra lub programem systemowym (np. w systemie UNIX). Interpreter wykonuje pewne polecenia wewnętrznie, tzn. moduł lub program interpretera dostarcza implementacji tych poleceń. Jeśli interpreter nie może wykonać wewnętrznie jakiegoś polecenia, uruchamia odpowiedni program (tzw. polecenie zewnętrzne), jako odrębny proces.
Programy systemowe (programy użytkowe systemu):
Zadania systemu operacyjnego:
Proces - uruchomiony program. Jeden program to może być wiele procesów, bo np. uruchomimy wiele razy ten jeden program. Każdy proces jest identyfikowany przez numer PID.
W systemie operacyjnym każdy proces posiada proces nadrzędny (rodzica), z kolei każdy proces może, poprzez wywołanie funkcji systemu operacyjnego, utworzyć swoje procesy potomne. W ten sposób tworzy się swego rodzaju drzewo procesów.
W skład procesu wchodzi:
W trakcie ładowania procesu do pamięci system operacyjny tworzy stos (stack) i stertę (heap).
Stos – do przechowywania zmiennych, parametrów funkcji, adresów powrotu. Sterta – do przechowywania dynamicznie alokowanych danych, np. listy
Stany procesu:
Czasami może być konieczne współbieżne wykonywanie pewnych fragmentów programu. Aby to zrealizować, program może zażądać utworzenia określonej liczby wątków, wykonujących wskazane części programu. Ta cecha systemu operacyjnego to wielowątkowość. W jednym procesie może być kilka wątków. Każdy wątek ma swój własny stos (posiada swoje zmienne lokalne)
Cecha systemu operacyjnego umożliwiająca równoczesne wykonywanie więcej niż jednego procesu (programu).
Jest jak policjant na skrzyżowaniu, który wskazuje, które auta mogą teraz przejechać przez skrzyżowanie. Jest to część systemu operacyjnego przełączająca procesy według polityki szeregowania zadań. Do jego zadań należy m.in. przełączanie kontekstu.
Planista krótkoterminowy ustala wartość priorytetu. Wybiera proces o najwyższym priorytecie do wykonania.

Możliwe jest zagłodzenie procesu, gdy dany proces nie jest w stanie zakończyć działania, ponieważ nie ma dostępu do procesora lub innego współdzielonego zasobu. Występuje najczęściej na skutek niewłaściwej pracy algorytmu szeregowania lub nadmiernego obciążenia systemu.
Zdarza się również tzw. zakleszczenie, czyli blokada wzajemna. Powstaje wtedy, gdy wiele zadań w tym samym czasie konkuruje o wyłączny dostęp do zasobów. Zakleszczenie:

Iteracja - czynność powtarzania (najczęściej wielokrotnego) tej samej instrukcji (albo wielu instrukcji) w pętli.
Rekurencja to w logice, programowaniu i w matematyce odwoływanie się np. funkcji lub definicji do samej siebie.
Najwięcej problemów związanych z rekurencją wiąże się z ograniczeniami stosu wywołań, a właściwie jego pojemności. Na stosie są odkładane kolejne wywołania danej metody i dopiero gdy dojdziemy do ostatniego elementu dane te są zbierane – bardzo łatwo więc o sytuację, gdy po prostu stos przepełnimy.
Silnia iteracyjnie: n! = 1 * 2 * 3...* n
Silnia rekurencyjnie: n! = n * (n-1)!
Ciąg Fibonacciego
Definicja: dla mamy
natomiast wyrazy 1 i 0 przyjmują wartość 1.
Fibonacci rekurencyjnie:
function FibR(n)
begin
if ( n=0 or n=1) then {
return 1
}
return FibR(n-1) + FibR(n-2)
end
Fibonacci iteracyjnie:
function FibI(n)
begin
tmp :=0 // zmienna tymczasowa (pomocnicza)
x := 1 // wyraz n-1
y := 1 // wyraz n-2
for i:=1 to n-1 step 1 {
tmp := y // zapamiętaj wyraz n-2
y := y+x // przesuń wyraz n-2 na kolejną wartość ci¡gu
x := tmp // przesuń wyraz n-1 na kolejną wartość ci¡gu
// czyli na warto±¢ wyrazu n-1 przed jego
// przesunięciem
}
return x
end
I mean..come on ;-;
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
Note: The default keyword must be used as the last statement in the switch, and it does not need a break. default can be the first statement on the list, but it makes no sense since only this statement will be executed.
break and default keywords are optional.
Without a break statement, every statement from the matched case label to the end of the switch, including the default, is executed.
| Condition | Action |
|---|---|
| Converted value matches that of the promoted controlling expression. | Control is transferred to the statement following that label. |
| None of the constants match the constants in the case labels; a default label is present. | Control is transferred to the default label. |
| None of the constants match the constants in the case labels; no default label is present. | Control is transferred to the statement after the switch statement. |
Podprogramy – wydzielona część programu wykonująca określony zbiór instrukcji, posiadająca swoją nazwę i stanowiąca pewną odrębną całość. Ich nazwy powinny informować o ich wyniku działania.
Ogólnie przyjęta konwencja (w przypadku C++) typ_rezultatu nazwa_funkcji( lista parametrów formalnych); na przykład:
bool isPrime(int);
Podprogramy dzielą się na dwa rodzaje:
Innym szczególnym przypadkiem są metody – funkcje, które są własnością klasy lub obiektu. Bez ich istnienia nie można się do nich odwołać.
W niektórych językach programowania nie istnieje powyższy podział.
Jeżeli chodzi o C++, formalnie procedury nie istnieją, jednak łatwo się domyślić, że ustawiając jako typ rezultatu void możemy utworzyć coś na jej wzór.
Przekazywanie parametrów do podprogramów odbywa się głównie na dwa sposoby:
int addOne(int number) {
return number++; //przez wartość
}
int addOne(int &number) {
return number++; //przez referencję
}
Programowanie strukturalne – paradygmat programowania opierający się na podziale kodu źródłowego programu na procedury i hierarchicznie ułożone bloki z wykorzystaniem struktur kontrolnych w postaci instrukcji wyboru i pętli. Język programowania zgodny z paradygmatem programowania strukturalnego nazywa się językiem strukturalnym.
Struktury kontrolne:
Programowanie obiektowe – paradygmat programowania, w którym programy definiuje się za pomocą obiektów – elementów łączących stan i zachowanie. Obiektowy program komputerowy wyrażony jest jako zbiór takich obiektów, komunikujących się pomiędzy sobą w celu wykonywania zadań.
| Programowanie strukturalne |
|
|
| Programowanie obiektowe |
|
|
aka enkapsulacja
Polega na ukrywaniu informacji - ukrywanie pewnych danych składowych lub metod w obiektach danej klasy tak, aby były one dostępne tylko dla metod wewnętrznych danej klasy lub dla metod z klas z nią zaprzyjaźnionych.
Z pełną enkapsulacją mamy do czynienia wtedy gdy dostęp do wszystkich pól w klasie jest możliwy tylko i wyłącznie poprzez metody, lub inaczej: gdy wszystkie pola w klasie znajdują się w sekcji prywatnej (lub chronionej)
Klasa to definicja obiektu, zawierająca stan obiektu, określony wartościami pól, oraz możliwe zachowanie, określone dostępnymi metodami.
Obiekt to utworzony egzemplarz (instancja) określonej klasy, który posiada własny, indywidualny stan i zbiór zachowań.
Metoda to funkcja lub procedura, skojarzona z ogółem klasy lub poszczególnymi jej obiektami; określa możliwe zachowania
Pole (Właściwość) to zmienna dowolnego typu, skojarzona z ogółem klasy lub poszczególnymi jej obiektami; określa aktualny stan obiektu
Dziedziczenie to mechanizm definiowania nowej klasy na bazie już istniejącej, wzbogacając ją o nowe pola, metody lub zmieniając zakres ich widoczności.
Struct - wszystkie składowe (pola i metody) są domyślnie publiczne
Class - wszystkie składowe (pola i metody) są domyślnie prywatne
Metoda
class MyClass {
void privateMethod(); //deklaracja w klasie
public:
void publicMethod() { //definicja w klasie
//donothing;
};
}
Definicja klasy musi zawierać przynajmniej deklarację metody
Definicja metody, często dla czytelności kodu, jest umieszczana poza klasą
void MyClass::privateMethod() { //definicja poza klasą
//this method is depressed
}
struct Obj {
int a, b; //od C++11 możliwa inicjalizacja w klasie, np.
//int a = 0;
Obj(int _a = 0, int _b = 0){ //konstruktor
a = _a;
b = _b;
}
};
{
Obj x, y(1), z(1,2), v = 3, u = {3,4}; //wywołania konstruktora
Obj t[5], *s = new Obj, *p = new Obj[3]; //wielokrotne
}
Konstruktor domyślny:
struct Obj {
int a, b;
Obj(){ //konstruktor domyślny
a = 0;
b = 0;
}
Obj()=default;//konstruktor domyślny bez inicjalizacji(C++11)
};
{
Obj x, t[5]; //wywołania konstruktora domyślnego
Obj *s = new Obj, *p = new Obj[3]; //tu też
}
struct Obj {
int a, b;
Obj(int _a, int _b = 0){ //1- lub 2-parametrowy konstruktor
a = _a;
b = _b;
}
};
{
Obj y(1), z(1, 2); //wywołania konstruktora
Obj x; //brak konstruktora domyślnego – błąd kompilacji!
}
Konstruktor kopiujący:
struct Obj {
int a, b;
... //inne konstruktory łącznie z domyślnym
Obj(const Obj &o){ //konstruktor kopiujący
a = o.a;
b = o.b;
}
};
{
Obj x;
Obj y(x), z = x; //wywołania konstruktora kopiującego
}
struct Obj {
int a, b;
... //konstruktory łącznie z domyślnym
~Obj(){...} //destruktor
~Obj()=default; //destruktor domyślny (C++11)
};
{
Obj x, *p = new Obj; //wywołania konstruktora
delete p; //jawne wywołanie destruktora (obiekt *p)
} //niejawne wywołanie destruktora (obiekt x)
Destruktory obiektów:
{
Obj x, *p = new Obj, z;
{ Obj y; } //destruktor dla obiektu y
delete p; //destruktor dla obiektu *p
} //destruktor dla obiektu z i dalej dla x
Kiedy wywoływany jest destruktor?
Dla każdej klasy kompilator tworzy automatycznie (o ile nie zdefiniowano ich jawnie) następujące metody:
struct Obj {
int a, b;
};
{
Obj x; //konstruktor domyślny, atrybuty są przypadkowe
Obj y = x; //konstruktor kopiujący
x = y; //operator przypisania
} //destruktor domyślny obiektów y i x
W programowaniu obiektowym jest to obiekt pozwalający na sekwencyjny dostęp do wszystkich elementów lub części zawartych w innym obiekcie, zwykle kontenerze lub liście.
Podstawowym celem iteratora jest pozwolić użytkownikowi przetworzyć każdy element w kolekcji bez konieczności zagłębiania się w jej wewnętrzną strukturę. Np.: przejść do kolejnego elementu, na koniec na początek. Użytkownik nie musi np. zajmować się tym, że odwoła się do nieistniejącego elementu.
W C++ iteratory są szeroko wykorzystywane w bibliotece STL. Iteratory stosuje się zwykle w parach, gdzie jeden jest używany do właściwej iteracji, zaś drugi oznacza koniec kolekcji.
Iteratory tworzone są przez odpowiadający im kontener standardowymi metodami, takimi jak begin() i end(). Iterator zwrócony przez begin() wskazuje na pierwszy element, podczas gdy iteratorzwrócony przez end() wskazuje na pozycję za ostatnim elementem kontenera.
int main() {
vector<int> ar = { 1, 2, 3, 4, 5 };
// Declaring iterator to a vector
vector<int>::iterator ptr;
// Displaying vector elements using begin() and end()
cout << "The vector elements are : ";
for (ptr = ar.begin(); ptr < ar.end(); ptr++)
cout << *ptr << " ";
return 0;
}
Output:
The vector elements are : 1 2 3 4 5
Just in case: przeciążenie operatorów slajd 7+ (Cybula) oraz slajd 8+ (Wardowski).
Selektory
x.set(4, 4.5);
INSERT INTO TABLE osoby VALUES (’Jan’, ’Kowalski’);
SELECT imie FROM osoby WHERE nazwisko = ’Kowalski’;
UPDATE osoby SET imie = ’Adam’;
DELETE FROM osoby WHERE nazwisko = ’Kowalski’;
CREATE TABLE osoby (imie VARCHAR(50), nazwisko VARCHAR(50));
Jest to mechanizm umożliwiający tworzenie nowych klas na podstawie klasy już istniejących w ten sposób, że nowa klasa przejmuje (dziedziczy) wszystkie metody drugiej klasy.
Zalety:
Klasa oryginalna, na podstawie której tworzymy nową, nazywamy klasą macierzystą.
Klasa, która dziedziczy funkcjonalność innej klasy nazywamy klasą potomną.
class Pracownik {
private:
enum {ILE = 20};
char imie[ILE];
char nazwisko[ILE];
char stanowisko[ILE];
double pensja;
public:
Pracownik(const char*, const char*, const char*, double p);
void wypiszDane() const;
void ustawPensja(double);
double getPensja() const;
};
class Dyrektor : public Pracownik {
private:
double dodatekFunkcyjny;
public:
Dyrektor(double, const char* i, const char*, const char*, double p);
Dyrektor(double dF, const Pracownik &);
double getDodatekFunkcyjny() {return dodatekFunkcyjny;}
void setDodatekFunkcyjny(double dF) {dodatekFunkcyjny = dF;}
};
Dwukropek oznacza, że klasa Dyrektor powstała z klasy Pracownik, która tutaj stanowi publiczną klasę macierzystą (dziedziczenie publiczne). Obiekt klasy potomnej zawiera wszystkie pola składowe i metody klasy macierzystej. Gdy dziedziczenie jest publiczne, to wszystkie składowe publiczne klasy macierzystej stają się składowymi publicznymi klasy potomnej. Dostęp do odziedziczonych prywatnych składowych jest możliwy poprzez odziedziczone publiczne lub chronione metody klasy macierzystej.
Obiekt klasy potomnej
Obiekt klasy Dyrektor ma następujące cechy:
W klasie potomnej powinny być zdefiniowane własne konstruktory, które dostarczają danych
zarówno dla nowych pól jak i odziedziczonych.
Klasa potomna może być uzupełniona o dodatkowe pola składowe i metody.
Konstruktory klasy potomnej
Klasa potomna nie może korzystać z prywatnych składowych klasy macierzystej, musi więc odwoływać się do nich za pomocą publicznego interfejsu klasy macierzystej. W konsekwencji konstruktory klasy potomnej mogą wykorzystywać konstruktory klasy macierzystej.
Podczas tworzenia obiektu klasy potomnej tworzony jest najpierw obiekt klasy macierzystej. Aby wywołać odpowiedni konstruktor klasy macierzystej, wykorzystuje się tzw. listę inicjatorów konstruktora (listę inicjalizacyjną).
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p) : Pracownik (i,n, s, p) {
dodatekFunkcyjny = dF;
}
//konstruktor bez listy inicjalizacyjne
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p = 0) {
dodatekFunkcyjny = dF;
}
//powyższy konstruktor jest równoważny poniższemu:
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p) : Pracownik() {
dodatekFunkcyjny = dF;
}
//konstruktor powodujący wywołanie konstruktora kopiującego:
Dyrektor::Dyrektor(double dF, const Pracownik & p) : Pracownik(p) {
dodatekFunkcyjny = dF;
}
Podczas likwidacji obiektu klasy potomnej w pierwszej kolejności wywoływany jest destruktor tej klasy, a następnie wywoływany jest destruktor klasy macierzystej.
Dyrektor anna(500,”Anna”, ”Lis”, ”Dyrektor”, 3000);
anna.wypiszDane();
Pracownik* p1;
p1 = &anna;
p1->wypiszDane();
Pracownik& p2 = anna;
p2.wypiszDane();
p1->setDodatekFunkcyjny(500); //błąd!!!, p1 wskazuje na obiekt klasy macierzystej
Pracownik p3();
Dyrektor& d1 = p3; //błąd!!!
Dyrektor* d2 = &p3; //błąd!!!
Inicjalizacja obiektu klasy macierzystej za pomocą obiektu klasy potomnej
Dyrektor dyr(300, ”Jan”, ”Kowalski”, ”Dyrektor”, 3000);
Pracownik p(dyr);
W powyższej sytuacji działa konstruktor kopiujący klasy macierzystej:
Pracownik(const Pracownik&);
Przypisanie obiektu klasy potomnej do obiektu klasy macierzystej
Dyrektor dyr(300, ”Jan”, ”Kowalski”, ”Dyrektor”, 3000);
Pracownik p;
p = dyr;
W powyższej sytuacji działa w sposób niejawny operator przypisania:
Pracownik& operator=(const Pracownik&);
W C++ wyróżniamy trzy rodzaje dziedziczenia:
Dziedziczenie - kontrola dostępu:

MyAbstractClass abclass; //błąd!
MyAbstractClass * p; //OK
Dziedziczenie wielokrotne zazwyczaj prowadzi do niejednoznaczności wywołań funkcji.
Najlepszym rozwiązaniem jest przedefiniowanie wszystkich metod w klasie, która dziedziczy z
wielu klas macierzystych. W przedefiniowanych metodach przeważnie wskazujemy w sposób
jawny, które wersje metod chcemy wywołać.
Mechanizm polegający na tym, że jedna metoda może występować w wielu różnych postaciach w zależności od kontekstu jej wywołania nazywamy polimorfizmem.
W celu wdrożenia polimorficznego działania dziedziczenia publicznego stosujemy:
Aby odpowiednia wersja metody została wywołana należy przed deklaracją metody umieścić słowo virtual. W definicji słowo virtual pomijamy.
virtual double getPensja(); //deklaracja metody dla klasy Dyrektor
...
double getPensja() { //definicja metody
return Pracownik::getPensja() + dodatekFunkcyjny;
}
W przypadku poprzedzenia deklaracji słowem virtual, odpowiednia wersja metody zostanie wywołana w oparciu o typ obiektu, do którego odwołuje się referencja lub wskaźnik.
Dyrektor anna;
Pracownik janek;
Pracownik& p1 = anna;
Pracownik& p2 = janek;
p1.getPensja(); //wywołana metoda Dyrektor::getPensja();
p2.getPensja(); //wywołana metoda Pracownik::getPensja();
W przypadku, gdy metoda przedefiniowana nie jest poprzedzona w części deklaracyjnej słowem virtual, wówczas sposób działania metody opiera się na typie referencji, a nie na typie obiektu.
Dyrektor anna;
Pracownik janek;
Pracownik& p1 = anna;
Pracownik& p2 = janek;
p1.getPensja(); //wywołana metoda Pracownik::getPensja();
p2.getPensja(); //wywołana metoda Pracownik::getPensja();
Zazwyczaj dobrą praktyką jest poprzedzanie w klasie macierzystej słowem virtual deklaracje tych metod, które są przedefiniowane w klasie potomnej. Zabieg ten pozwala wybrać odpowiednie wersje metod, na podstawie obiektu, na rzecz którego są one wywoływane, a nie na postawie referencji lub wskaźnika.
Poprzedzenie destruktorów słowem virtual powoduje, że podczas destrukcji obiektu zostanie wywołany odpowiedni kod destruktora.
Wiązanie nazwy funkcji polega na określeniu odpowiedniego bloku wykonywalnego (w kodzie skompilowanym), który ma zostać użyty.
Wiązanie statyczne to wiązanie, które jest realizowane podczas kompilacji kodu źródłowego.
Wiązanie dynamiczne, to odpowiedni mechanizm, który pozwala wybrać odpowiednią metodę wirtualną podczas działania programu.
Uwaga Wiązanie dynamiczne zachodzi wówczas, gdy odpowiednie metody wywoływane są przez wskaźniki lub referencje.
Polimorfizm statyczny jest często implementowany za pomocą szablonów. Jest on nieograniczony, bo interfejsy typów uczestniczących w polimorfizmie nie są z góry określone.
Szablony służą do tworzenia ogólnych deklaracji klas (lub funkcji). W ten sposób realizowana jest koncepcja tzw. typów sparametryzowanych. Typ jest argumentem przekazywanym do ogólnego wzorca klasy lub funkcji.
Szablony pozwalają na wielokrotne wykorzystanie istniejącego kodu źródłowego struktury danych dla wielu wersji tej struktury z tym samym interfejsem, ale różnymi typami dla wewnętrznych komponentów (programowanie generyczne/uogólnione, struktury parametryzowane)
template <typename T>
class Punkt {
private:
T x, y;
public:
Punkt();
Punkt(T,T);
T getX();
T getY();
void setXY(T,T);
void wypisz();
};
template <typename T>
Punkt<T>::Punkt() {
x = y = 0;
}
template <typename T>
T Punkt<T>::getX() {
return x;
}
...
Chcąc wygenerować klasę na podstawie zdefiniowanego szablonu należy jawnie określić typ parametru (tzn. dokonać jawnej konkretyzacji typu).
#include <iostream>
#include "Punkttp.h"
using namespace std;
int main() {
Punkt<int> p(3,2);
cout << p.getX();
Punkt<double> z(3.2,2.1);
z.setXY(5.01,3);
return 0;
}
Konkretyzując klasę możemy użyć zarówno typu wbudowanego jak i obiektu jakiejś klasy.
W języku C++ możemy używać szablony, które posiadają więcej niż jeden argument typu. Korzystając z tej możliwości możemy utworzyć klasę do przechowywania dwóch elementów różnych typów.
template <typename T1, typename T2>
class Pair {
private: T1 x, T2 y;
public:
T1 & first(const T1 & f) {x = f; return x;};
T2 & second(const T2 & s) {y = s; return y;};
T1 first() const {return x;}
T2 second() const {return y;}
Pair(const T1 & f, const T2 & s) : x(f), y(s) {}
Pair(){}
};
```## 21. Listy i drzewa oraz ich zastosowania. Stosy i kolejki.
<a href="<link_to_resource_local_or_online_here>"></a><b></b>
__Listy__
Lista to ciąg elementów, gdzie każdy zawiera atrybuty: ***key***, ***next*** oraz ***previous***. Wartość każdego z tych elementów odczytujemy przez ***key[x]***. Listy reprezentujemy poprzez obiekt, zawierający atrybuty ***head*** oraz ***tail***, wskazujące odpowiednio na początek i koniec listy.
Listy dzielimy na 3 typy:
1. listy jednokierunkowe
2. Listy dwukierunkowe
3. Listy cykliczne
<br />
W liście ***jednokierunkowej*** każdy z elementów wskazuje na element następny, czyli dla każdego x, next[x] wskazuje na kolejny. Ostatni element listy wskazuje na pusty element ***NIL***.

<br />
W liście ***dwukierunkowej*** każdy element zawiera trzy atrybuty. Oprócz atrybutu next zawiera także *previous* wskazujący na poprzedni element listy. Na pusty element ***NIL*** wskazuje zarówno pierwszy jak i ostatni element listy.

<br />
Listą ***cykliczną*** nazywamy listę, w której ostatni element **zamiast wskazywać** na pusty element **NIL**, wskazuje na pierwszy element listy. **Nie występują** tutaj atrybuty **head i tail**.
<br />

<br />
__Stos__
Stos to liniowa struktura danych, gdzie elementy przetwarzane są w kolejności od tego, który pojawił się najpóźniej (jest na górze stosu) do tego, który pojawił się na samym początku (na dole stosu).
Poszczególne elementy można przeglądać, lecz by pobrać element znajdujący się poniżej, trzeba pobrać ze stosu wszystkie elementy znajdujące się nad nim.
W algorytmach stos reprezentowany jest przez strukturę **LIFO (Last In First Out)**.
<br />
__Kolejka__
Kolejka jest strukturą działającą przeciwnie do stosu. Dane są przetwarzane w kolejności ich pojawienia się, tzn.: zaczynając od tego, który pojawił się na początku, kończąc na tym, który znalazł się na samym końcu.
W algorytmach kolejka reprezentowana jest poprzez strukturę ***FIFO (First In First Out)***.
<br />
__Drzewa__
Drzewo składa się z elementów , które posiadają **trzy** atrybuty: ***key***, ***left*** oraz ***right***.
Drzewo reprezentowane jest przez obiekt z atrybutem ***root (korzeń)***. Kolejne elementy są jego potomkami.

W informatyce drzewo wykorzystywane jest do budowy ***drzew decyzyjnych***, które są podstawą działania takich algorytmów jak ***min-max*** (wyznaczanie optymalnych ruchów).
## 22. Grafy i metody ich przeszukiwania. Zastosowania.
__Grafy__
**Graf** To struktura matematyczna służąca do przedstawiania i badania relacji między obiektami. W uproszczeniu **Graf to zbiór wierzchołków, które mogą być połączone krawędziami w taki sposób, że każda krawędź kończy się i zaczyna w którymś z wierzchołków**.
<br />
***Grafem nieskierowanym*** nazywamy parę **G=(V, E)**, gdzie **V** jest pewnym zbiorem skończonym zwanym **zbiorem wierzchołków grafu G**.
Natomiast **E** jest zbiorem nieuporządkowanych par **{u, v}** gdzie ***u, v $\isin$ V*** oraz ***u != v***.
Zbiór **E** nazywamy zbiorem krawędzi grafu **G**.

Jeśli ***{u, v}*** jest krawędzią grafu nieskierowanego **G**, to mówimy, że ***{u, v}*** jest ***incydentna*** z wierzchołkami **u** i **v**.
**Stopniem** wierzchołka w grafie nieskierowanym nazywamy ***liczbę incydentnych z nim krawędzi***. Pętlę liczymy za 2.
<br />
***Grafem skierowanym*** nazywamy parę ***G=(V, E)***, gdzie **V** jest pewnym zbiorem skończonym zwanym **zbiorem wierzchołków grafu G**.
Natomiast **E** - zbiór krawędzi grafu **G**.
**G** - zbiór uporządkowanych par ***{u, v}** oznaczanych **(u, v)**, gdzie ***u, v $\isin$ V***

**Stopniem** wierzchołka w grafie skierowanym nazywamy **sumę liczby krawędzi wchodzących do wierzchołka i wychodzących z tego wierzchołka**
<br/>
**Rząd grafu** - liczba wierzchołków w grafie.
**Rozmiar grafu** - liczba krawędzi w grafie.
**Droga (ścieżka)** - drogą w grafie będziemy nazywać ciąg krawędzi taki, że koniec jednej stanowi początek następnej. Drogę nazywamy **prostą**, gdy **wszystkie jej wierzchołki są różne**.
**Osiągalność** - mówimy, że **v** jest osiągalny z **u**, gdy istnieje droga z **u** do **v**.
**Cykl** - cyklem nazywamy zamkniętą drogę *x<sub>1</sub>x<sub>2</sub>x<sub>3</sub>...x<sub>n</sub>x<sub>1</sub>* w grafie skierowanym, gdzie to wierzchołki *x<sub>1</sub>x<sub>2</sub>...x<sub>n</sub>* to wierzchołki drogi, która jest długości co najmniej 1. **Gdy wszystkie wierzchołki są różne to cykl nazywamy prostym**. **Cykl o długości 1 nazywamy pętlą**.
Mówimy, że ścieżka ***<v<sub>0</sub>, v<sub>1</sub>, ..., v<sub>k</sub>>*** tworzy **cykl** w grafie **nieskierowanym**, gdy **v<sub>0</sub> = v<sub>k</sub>**, **v<sub>1</sub> ... v<sub>k</sub>** są różne oraz **k >=2**
Graf niezawierający cykli nazywamy grafem **acyklicznym**.
Acykliczny graf nieskierowany nazywamy **lasem**.
**Graf prosty** to graf bez krawędzi wielokrotnych i bez pętli.
**Graf regularny** to fraf, w którym wszystkie wierzchołki są tego samego stopnia.
**Graf pusty** to graf, w którym w ogólne nie ma krawędzi (są same wierzchołki izolowane).
**Graf pełny** to graf prosty, w którym każdy wierzchołek jest połączony krawędzią z każdym.
<br/>
**Graf jest spójny**, gdy każda para różnych wierzchołków jest połaczona drogą w tym grafie.
Spójny podgraf grafu **G**, który nie jest zawarty w żadnym większym spójnym podgrafie tego grafu, nazywamy **składową grafu G**.
Spójny, acykliczny graf nieskierowany nazywamy **drzewem (wolnym)**.
**Cykl Eulera** - droga zamknięta przechodząca przez każdą krawędź grafu dokładnie raz.
**Droga Eulera** - droga przechodząca przez każdą krawędź grafu dokładnie raz.
Graf, który posiada cykl Eulera **Musi mieć wszystkie wierzchołki stopnia parzystego**.
Graf, który posiada drogę Eulera ma **albo dokładnie dwa wierzchołki stopnia nieparzystego, albo nie ma w ogóle takich wierzchołków**.
Graf spójny, mający dokładnie 2 wierzchołki stopnia nieparzystego **posiada drogę Eulera**.
<br />
__Formy reprezentacji grafów__
- **Macierz sąsiedztwa**
Macierzą sąsiedztwa grafu (skierowanego lub nie) nazywamy macierz **M** o wymiarze ***VxV***, w której wartości reprezentują wagę połączeń pomiędzy wierzchołkami, 1 gdy połączone, 0 gdy nie ma.

- **Lista sąsiedztwa**
Dane zapisywane są w postaci listy obiektów zawierających wierzchołek grafu, wraz z listą wierzchołków sąsiednich. W przypadku grafu nieskierowanego listy są dłuższe, ponieważ muszą odzwierciedlać krawędzie w obu kierunkach.

- **Macierz incydencji**
Macierz incydencji jest macierzą **A** o wymiarze **n x m**, gdzie **n** oznacza liczbę wierzchołków grafu, natomiast **m** liczbę jego krawędzi. Każdy wiersz tej macierzy odwzorowuje jeden wierzchołek grafu. Każda kolumna odwzorowuje jedną krawędź. Zawartość komurki **A[i, j]** określa powiązanie (incydencję) wierzchołka **v<sub>i</sub>** z krawędzią **e<sub>j</sub>** w sposób następujący:

Jeśli graf jest nieskierowany, to definicję macierzy należy uprościć:

<br/>
__Zastosowania__
**Mapy** - Aby znaleźć najkrótszą drogę by dostać się z jednego miejsca do drugiego można wykorzystać graf, którego wierzchołki będą odpowiadały miejscowością a krawędzie drogom.
**Dokumenty hipertekstowe** - Przeszukując internet napotykamy dokumenty, które zawierają odnośniki do innych dokumentów - internet jest grafem, którego wierzchołkami sa dokumenty a krawędziami odsyłacze.
**Sieci** - Sieć komputerowa zbudowana jest z komputerów, które przesyłają między sobą informacje. Komputery w danej sieci reprezentowane są przez wierzchołki grafu, a połączenia między nimi krawędziami.
**Struktura programu** - Kompilator buduje graf reprezentujący strukturę wywołań podprogramów w kompilowanym programie. Wierzchołkami grafu są różne funkcje, natomiast krawędzie są kojarzone z wywołaniem funkcji./
## 23. Metody projektowania algorytmów (dziel i rządź, programowanie dynamiczne i algorytmy zachłanne).
- **Dziel i rządź**
Polega na rekurencyjnym dzieleniu problemu na mniejsze podproblemy. Dzielenie trwa dopóni nie uzyskamy problemów, które da się w prosty sposób rozwiązać.
Algorytmy wykorzystujące metodę "dziel i rządź":
- Sortowanie przez wybieranie
- Sortowanie przez wstawianie
- Sortowanie przez scalanie
- Quicksort
<br/>
- **Programowanie dynamiczne**
Jest stosowane głównie do rozwiązywania problemów optymalizacyjnych. Jest alternatywą dla niektórych zagadnień rozwiązywanych metodami zachłannymi. Wyniki poszczególnych obliczeń są zapamiętywane w pomocniczej tablicy, która jest wykorzystywana w kolejnych krokach. Eliminuje to konieczność wielokrotnego powtarzania tych samych obliczeń.
Algorytmy wykorzystujące programowanie dynamiczne:
- Algorytm Bellmana-Forda
- Algorytm Helda-Karpa
- Algorytm wykorzystujący problem wydawania reszty
<br/>
- **Algorytm zachłanny**
W każdym kroku dokonuje wyboru będącego na daną chwilę tym najlepszym. Podejmuje decyzje optymalne tylko lokalnie. Kontynuuje działania wynikające z poprzednich decyzji.
Algorytmy wykorzystujące metodę zachłanną:
- Algorytm Dijkstry (poszukiwanie najkrótszych ścierzek)
- Algorytm Kruskala (poszukujący minimalnego drzewa rozpinającego)
## 24. Elementarne i nieelementarne metody sortowania.
Elementarne metody sortowania:
- **Sortowanie przez selekcję (selection sort)** - Jego czas działania jest określany z góry O(n<sup>2</sup>). Sortowanie to jest najlepsze, spośród innych elementarnych do sortowania elementów o małych kluczach i dużych polach, ponieważ wykonuje najmniej wstawień. W pierwszym przebiegu algorytm znajduje najmniejszy element w tablicy i zamienia go z pierwszym. W drugim algorytm znajduje najmniejszy element w podtablicy i zamienia go z drugim. Tak aż do zamiany r-tego elementu z r-1 elementem.
- **Sortowanie bąbelkowe** - Czas działania jest z góry określony przez O(n<sup>2</sup>) - algorytm wykonuje w najgorszym i średnim przypadku podobną ilość porównań i zamian. Zadada działania opiera się na cyklicznym porównywaniu par sąsiadujących elementów i zamianie ich kolejności w przypadku niespełniania kryterium porządkowego zbioru. Operację tę wykonujemy dotąd, aż cały zbiór zostanie posortowany.
<br/>
Nieelementarne metody sortowania:
- **Quicksort (sortowanie szybkie)** - Średnia złożoność obliczeniowa O(*n log n*)Bazuje na strategii dziel i rządź. Problem dzielimy rekurencyjnie na podproblemy a następnie łączymy w jedno rozwiązanie. Z tablicy wybiera się element rozdzielający, po czym tablica jest dzielona na dwa fragmenty: do początkowego przenoszone są wszystkie elementy nie większe od rozdzielającego, do końcowego wszystkie większe. Potem sortuje się osobno początkową i końcową część tablicy. Rekurencję kończy się, gdy kolejny fragment uzyskany z podziału zawiera pojedynczy element, jako że jednoelementowa tablica nie wymaga sortowania.
- **Sortowanie pozycyjne** - Algorytm porządkujący stabilnie ciągi wartości (liczb, słów) względem konkretnych cyfr, znaków itp, kolejno od najmniej znaczących do najbardziej znaczących pozycji. Złożoność obliczeniowa jest równa O(d(n+k)), gdzie k to liczba różnych cyfr, a d liczba cyfr w kluczach. Wymaga O(n+k) dodatkowej pamięci.
## 25. Elementarne metody wyszukiwania. Haszowanie.
**Wyszukiwanie liniowe/sekwencyjne**
- Polega na przeglądaniu kolejnych elementów zbioru **Z**
- W przypadku odnalezienia elementu, który posiada odpowiednie własności, zwraca jego pozycje w zbiorze i kończy pracę.
- W przypadku pesymistycznym, gdy poszukiwanego elementu nie ma w zbiorze lub też znajduje się on na samym końcu zbioru, algorytm musi wykonać przynajmniej **n** obiegów pętli sprawdzającej poszczególne elementy
- klasa złożoności obliczeniowej jest równa **O(n)**
- W przypadku poszukiwania wszystkich wystąpień poszukiwanej własności elementu, algorytm po zwrocie pierwszej odnalezionej pozycji kontunuuje pracę od następnego indeksu.
<br/>
**Wyszukiwanie binarne**
- Opiera się na metodzie **dziel i rządź** oraz działa na uporządkowanych tablicach
- Polega na sprawdzeniu środkowego elementu zbioru oraz przyjęciu nowego podzbioru, gdy środkowy element nie spełnia kryteriów wyszukiwania
- Wyszukiwanie kontynuowane jest w podzbiorze spełniającym warunek porównania **mniejsze-większe**
- W przypadku odnalezienia elementu, posiadającego odpowiednie własności, zwraca on jego pozycję w tablicy i kończy pracę
- Złożoność obliczeniowa równa **O(log<sub>2</sub>n)**
- W przypadku tablicy o milionie elementów, algorytm musi sprawdzić maksymalnie 20 pozycji
<br/>
**Wyszukiwanie max lub min**
- Opiera się na metodzie wyszukiwania liniowego
- Przyjmuje pierwszy element zbioru za tymczasowy maksymalny/minimalny a następnie porównuje go z kolejnym elementem i na podstawie wyniku porównania może przyjąć nowy tymczasowy element maksymalny/minimalny
- Po przejściu przez wszystkie elementy zbioru, wartość elementu tymczasowego zostaje przyjęta jako maksimum lub minimum zbioru
- Złożonośc obliczeniowa równa **O(n)**
<br/>
**Naiwne wyszukiwanie wzorca w tekście**
- Algorytm ustawia okno o długości wzorca **p** na pierwszej pozycji w łańcuchu **s** a następnie sprawdza czy zawartość wzorca **p** i porównywanego fragmentu łańcucha **s** są sobie równe
- W przypadku pozytywnym pozycja okna jest zwracana jako wynik
- Po porównaniu okno przesuwa się o jedną pozycje w prawo i cała procedura powtarza się, dopóki okno nie wyjdzie poza koniec łańcucha **s**
- Posiada złożoność obliczeniową równą **O(n x m)** pesymistycznie, oraz **o(n)** w najlepszym przypadku.
<br/>
**n** - długość łańcucha
<br/>
**m** - długość wzorca
<br/>
**Haszowanie**
- Technika rozwiązywania ogólnego problemu słownika, czyli takiego zorganizowania struktur danych i algorytmów, aby można było w miarę efektywnie przechowywać i wyszukiwać elementy należące do pewnego dużego zbioru danych (uniwersum),
- Przykładem tablicy z haszowaniem jest książka telefoniczna, w której kluczem są imie i nazwisko a wyszukiwaną informacją jest numer telefonu.
- Czas uzyskania informacji jest **niezależny** od rozmiaru tablicy lub położenia elementu
- W najprostszym przypadku wartość **funkcji mieszającej** dla danego **klucza** wyznacza **indeks** szukanej informacji w tablicy (złożoność obliczeniowa wynosi **O(1)**)
- Może wystąpić problem **kolizji**, czyli przypisania przez funkcję mieszającą tej samej wartości dwóm różnym kluczom
**Unikanie kolizji**
- Zastąpienie istniejącego elementu lub rezygnacja ze wstawienia nowego elementu
- **Metoda Łańcuchowa** - przechowywanie elementów o tej samej wartości wewnątrz listy lib drzewa związanych z danym indeksem (pesymistycznie **O(n)**)
- **Adresowanie Otwarte** - nowy element wstawia się w innym miejscu niż wynikałoby to z wartości funkcji mieszającej a nowy indeks określany jest przez dodanie do wartości tzw. funkcji przyrostu **p(i)**, gdzie **i** oznacza numer próby (liczba kolizji)
- **Współczynnik wypełnienia** - iloraz liczby elementów zapisanych w tablicy mieszającej **(m)** od fizycznego rozmiaru tablicy **(n)**, czyli **$a$ = m/n**. Dzięki temu można przewidzieć prawdopodobieństwo wystąpienia kolizji i odpowiednio skorygować fizyczny rozmiar tablicy
- **Haszowanie kukułcze** - stosuje dwie tablice i dwie odpowiadające im funkcje haszujące. Do momentu kolizji elementy wstawiane są do pierwszej tablicy za pomocą pierwszej funkcji haszującej. W wypadku kolizji element wstawiany jest do drugiej tablicy przez drugą funkcję. Jeśli ponownie nastąpi kolizja, to zastępujemy istniejący już obiekt a dla niego zostaje uruchomiona ponowna procedura wstawiania, jednak tym razem na siłę będzie wstawiony do pierwszej tablicy. W przypadku zapętlenia się algorytmu losowane są nowe funkcje haszujące i wszystkie elementy tablucy zostają ponownie przemieszane. Odczyt elementu z tablicy odbywa się zawsze w czasie stałym.
<br/>
**Haszowanie - zastosowania**
- kompilatory, interpretery (w dynamicznych językach obiektowych)
- bazy danych - indeksowanie, łączenie, grupowanie
- analiza i agregacja danych
- trasowanie
- systemy pamięci podręcznej
- monitorowanie
- implementacja zbiorów
- mapowanie
- kompresja danych
- wyszukiwanie wzorca w tekście
<br/>
**Haszowanie - wady**
- Współczesne procesory wykorzystują pamięć podręczną, która przyspiesza odwołania do komórek pamięci operacyjnej, gdy te są zgrupowane blisko siebie. Zastosowanie tablicy mieszającej (z haszowaniem) dla małej liczby elementów może być wolniejsze niż zastosowanie zwykłej tablicy przeszukującej sekwencyjnie
- Występuje ryzyko dużej złożoności obliczeniowej w pesymistycznym przypadku wyszukiwania wynoszącej **O(n)**
- Obliczenie wartości dobrej funkcji haszującej (eliminującej kolizje) może być kosztowne względem czasu lub zasobów pamięci
## 26. Złożoność obliczeniowa algorytmu. Przykłady.
Mierzymy liczbę operacji wykonanych na modelu. Następnie próbujemy znaleźć funkcję, która będzie opisywała liczbę operacji w zależności od wejścia algorytmu. Funkcje te możemy porównać ze sobą.

Ile mamy tu operacji? Przypisanie, pętla for. Jej ciało zawiera jedną operację. Sama pętla wykona się dokładnie tyle razy ule jest elementów tablicy numbers. Liczbę tych elementów określimy jako *n*. Na końcu mamy instrukcję return *sum*.
Dodając do siebie otrzymujemy wzór:
*<center>f(n) = 1+n+1 = n+2</center>*
Zatem złożoność naszego algotyrmu opisana jest przez funkcję *f(n) = n+2*. Tak więc wyznacza się ją poprostu licząc operacje.
Jak oszacować rząd złożoności funkcji?
Wyobraźmy sobie pewien algorytm. Funkcja, która go opisuje to np.: *f(n) = n<sup>3</sup> - 6n<sup>2</sup> + 4n + 12*
Argument n to rozmiar danych wejściowych do algorytmu. Wykres tej funkcji wygląda następująco:

**Notacja Dużego O** zakłada, że istnieje funkcja *g(n)*, dla której spełniona jest poniższa wartość:
$\forall$ n $\geqslant$ n<sub>0</sub> : f(n) $\leqslant$ c $\cdot$ g(n)
Oznacza to, że wynik funkcji *g(n)* pomnożony przez jakąś stałą c, będzie większy bądź równy wynikowi funkcji *f(n)*. Własność ta jest spełniona dla wszystkich *n*, które będą większe od n<sub>0</sub>. Jeszcze łatwiej wygląda to na wykresie:

Pokazuje on dwie funkcje. Pierwszą z poprzedniego wykresu. Druga to wykres funkcji *g(n) = n<sup>3</sup>*. Od pewnego punktu zielona linia jest zawsze ponad czerwoną linią. To nic innego jak oszacowanie z góry. To właśnie robi notacja O. Zatem w naszym przypadku nasza funkcja *f(n)* ma złożoność *O(n<sup>3</sup>)*
## 27. Pojęcie bazy danych - funkcje i możliwości.
Baza danych jest zbiorem danych oraz narzędzi **Zystemu Zarządzania Bazą Danych (SZBD)** przeznaczonego do zarządzania nią oraz gromadzenia, przekształcania i wyszukiwania danych.
To zbiór usystematyzowanych informacji (danych), który dotyczy rzeczywistości a konkretnie określonego jej fragmentu (wycinka), który reprezentuje. Fragment ten określamy mianem obszaru analizy.
**Cechy bazy danych**
- **Trwałośc danych** - oznacza możliwość przechowywania danych w pamięci masowej (trwałej) komputera
- **Niezależność danych** - pozwala osiągnąć większą elastyczność, ponieważ programy wymieniające informacje z bazą danych są niezależne od przechowywania danych na dysku i szczegółów reprezentacji danych na dysku
- **Ochrona danych** - baza danych oferuje mechanizmy kontroli dostępu do danych w sposób umożliwiający użytkowanie danych wyłącznie przez uprawnionych do tego użytkowników
- **Integralność danych** - zgodność z rzeczywistością. Dane w bazie danych są odwzorowaniem rzeczywistości
- **Współdzielenie danych** - poszczególne fragmenty danych mogą być używane przez kilku użytkowników jednocześnie (dostęp współbieżny)
- **Abstrakcja danych** - dane opisują tylko istotne aspekty obiektów świata rzeczywistego
- **Integracja danych** = gwarantująca, że dane i związki między nimi nie powtarzają się jeśli nie jest to konieczne ale wszelkie zmiany w obrębie bazy nie powodują wieloznaczności
<br/>
**System zarządzania bazą danych (SZBD)** obsługuje użytkowników bazy danych, umożliwiając im eklploatację oraz tworzenie baz danych. By stworzyć i zaprojektować bazę danych, nalezy ją zidentyfikować, a do tego konieczne jest określenie typów przechowywanych w niej danych. Istotną rolę odgrywa również wyznaczenie użytkowników oraz ich praw dostępu.
**Właściwości bazy danych (funkcje SZBD)**
- Tworzenie struktur baz danych
- Wykonywanie operacji CRUD (Create, Read, Update, Delete)
- Obsługa zapytań (selekcjonowanie danych)
- Generowanie raportów i zestawień
- Administracja bazą danych
<br/>
**Podział baz danych**
- **Model relacyjno-obiektowy** jest mieszanym modelem bazodanowym, pozwala on w relacyjnych tabelach tworzyć kolumny, w których przechowywane są dane typu obiektowego, pozwala na definiowanie zmiennych oraz metod, które będą wykonywane na danych wprowadzancych do obiektu. Podstawa wielodostępu: identyfikatory użytkowników i ich hasła, procedura logowania system praw dostępu i uprawnień, grupy użytkowników
- **Obiektowy model danych** opiera się na koncepcji obiektów (podobnie jak w
projektowaniu obiektowym – obiekt jest odwzorowaniem rzeczywistości lub abstrakcji).
Odwołania do określonego obiektu w tym modelu bazy danych są wykonywane za
pomocą interfejsu, dzięki któremu są zachowane integralność i bezpieczeństwo danych.
- **Relacyjny model danych** w najprostszym ujęciu w modelu relacyjnym dane grupowane
są w relacje, które reprezentowane są przez tablice. Relacje są pewnym zbiorem
rekordów o identycznej strukturze wewnętrznie powiązanych za pomocą związków
zachodzących pomiędzy danymi. Relacje zgrupowane są w tzw. schematy bazy danych.
Relacją może być tabela zawierająca dane teleadresowe pracowników, zaś schemat
może zawierać wszystkie dane dotyczące firmy. Takie podejście w porównaniu do innych
modeli danych ułatwia wprowadzanie zmian, zmniejsza możliwość pomyłek, ale dzieje się
to kosztem wydajności. W 1985 r. Edgar Frank Codd (twórca) przedstawił 12 zasad
opisujących model relacyjny baz danych.
<br/>
**Postulaty Codda**
- **Postulat informacyjny** – dane są reprezentowane jedynie poprzez wartości atrybutów wierszach tabel.
- **Postulat dostępu** – każda wartość w bazie danych jest dostępna poprzez podanie nazwy tabeli, atrybutu i wartości
klucza podstawowego.
- **Postulat dotyczący wartości NULL** - dostępna jest specjalna wartość NULL dla reprezentacji zarówno wartości
nieokreślonej, jak i nieadekwatnej.
- **Postulat dotyczący katalogu** – wymaga się, aby system obsługiwał wbudowany katalog relacyjny z bieżącym
dostępem dla uprawnionych użytkowników.
- **Postulat języka danych** – system musi dostarczać pełny język przetwarzania danych, który może być używany zarówno
w trybie interaktywnym, jak i w obrębie programów aplikacyjnych, obsługuje operacje definiowania danych, operacje
manipulowania danymi, ograniczenia związane z bezpieczeństwem i integralnością oraz operacje zarządzania
transakcjami.
- **Postulat modyfikowalności perspektyw** – system musi umożliwiać modyfikowanie perspektyw, o ile jest ono semantycznie
realizowalne.
- **Postulat modyfikowalności danych** – system musi umożliwiać operacje modyfikacji danych, musi obsługiwać operatory
INSERT, UPDATE oraz DELETE.
- **Postulat fizycznej niezależności danych** – zmiany fizycznej reprezentacji danych i organizacji dostępu nie wpływają na
aplikacje.
- **Postulat logicznej niezależności danych** – zmiany wartości w tabelach nie wpływają na aplikacje.
- **Postulat niezależności więzów spójności** – więzy spójności są definiowane w bazie i nie zależą od aplikacji.
- **Postulat niezależności dystrybucyjnej** – działanie aplikacji nie zależy od modyfikacji i dystrybucji bazy.
- **Postulat bezpieczeństwa względem operacji niskiego poziomu** — operacje niskiego poziomu nie mogą naruszać modelu relacyjnego i więzów
<br/>
**Elementy relacyjnej bazy danych**
- **Encja** – rodzaj obiektu przechowywanego w bazie. Na przykład towar czy producent. Odpowiednikiem w
programowaniu obiektowym jest klasa.
- **Atrybut** – każda encja ma swoje właściwości. Na przykład pracownik ma numer telefonu, imię czy nazwisko. Każdy z
tych elementów to atrybut. Podobnie jak w programowaniu obiektowym instancję mają swoje atrybuty. Atrybuty
mogą mieć różne typy (np. varchar czyli string).
- **Krotka** – Pojedyncza krotka to wiersz w tabeli. Zbierając kilka wierszy tworzy się relacja. Np. relacja „ubrania” będzie
zawierała wiersze z typami ubrań oraz ich atrybutami.
- **Klucz główny** – zbiór atrybutów (kolumn w tabeli) tworzy klucz główny. Jest to unikalny identyfikator dla każdego wiersza
w tabeli. W większości przypadków tabele zawierają dodatkową kolumnę która zawiera identyfikator. Zazwyczaj jest to
liczba odpowiadająca numerowi wiersza.
- **Klucz obcy** – przez to że tabele mogą być ze sobą powiązane musimy mieć również klucz obcy. Jest to dodatkowa
kolumna (kolumny), która przekazuje zależność. Np. produkty mogą mieć swój klucz główny, a jako klucz obcy będzie
ich producent.
<br/>
KONIEC SLAJD 186!!!
## 28. Relacja i jej atrybuty w bazach danych.
**Rodzaje powiązań w relacyjnej bazie danych**
- **Jeden do jednego** – mając dwie tabele A i B występuje wtedy, gdy każdemu rekordowi z tabeli A jest
przyporządkowany jeden rekord z tabeli B i na odwrót. Np. numer rejestracyjny i samochód.
- **Jeden do wielu** – jest najczęściej używanym typem połączeń. Pomiędzy tabelami A i B występuje wtedy, gdy
pojedynczemu rekordowi z tabeli A jest podporządkowany jeden lub wiele rekordów z tabeli B, natomiast
pojedynczemu rekordowi z tabeli B jest przyporządkowany dokładnie jeden rekord z tabeli A.
- **Wiele do wielu** - pomiędzy tabelami A i B
występuje wtedy, gdy pojedynczemu rekordowi
z tabeli A jest przyporządkowany jeden lub wiele
rekordów z tabeli B i na odwrót. Taka sytuacja
będzie np. w relacji nauczycieli do uczniów.
Każdy nauczyciel ma wielu uczniów i każdego
ucznia uczą różni nauczyciele
**Klucz główny**
Dość często spotykanym problemem na etapie projektowania bazy danych jest określenie, która
kolumna (kolumny) będzie pełnić funkcję klucza głównego. Ponieważ każdy wiersz w tabel musi
my jednoznacznie zidentyfikować , zachodzi potrzeba wybrania atrybutów (kolumn), które
spełniają to zadanie. Klucz główny odgrywa bardzo ważną rolę w tabeli (relacji), dlatego jego
wybór powinien zostać poprzedzony analizą typowanych przez nas kolumn pod kątem
wymienionych poniżej własności:
- **trwałość** – wartość kolumny powinna być stale obecna w wierszu, oznacza to , że kolumna
taka (należąca do klucza głównego) nie może zawierać wartości NULL.
- **unikatowość** – wartość klucza dla każdego wiersza powinna być unikatowa, ponieważ w
niepowtarzalny sposób powinien on identyfikować każdą krotkę (wiersz tabeli). Może się
zdarzyć, że taki niepowtarzalny identyfikator otrzymamy, umieszczając w kluczu głównym
więcej niż jedną kolumnę. Kombinacja wartości, trzech kolumn, które należeć będą do
klucza, będzie unikatowa i jednoznacznie zidentyfikuje każdą krotkę.
- **stabilność** – wartości klucza nie powinny podlegać zmianom. Nie powinno się jako kluczy
głównych używać kolumn przechowujących wartości nietrwałe, np. numer telefonu
komórkowego, ponieważ mimo jego unikatowości każdy człowiek może go zmienić.
Aby jednoznacznie zidentyfikować wiersz tabeli, stosuje się atrybut (kolumnę), której
poszczególne wartości dla kolejnych krotek (wierszy) będą niepowtarzalne
Atrybut będący kluczem głównym możemy stworzyć sztucznie dla przykładu wprowadzając
kolejne numerowanie wierszy 1, 2, 3, 4, 5 itd., pod warunkiem że każdy wiersz ma inny numer.
Możemy również posłużyć się określoną cechą (atrybutem) opisywanej rzeczywistości (encji), np.
dokonując spisu ludności, możemy posłużyć się numerem PESEL. Ponieważ każdy człowiek ma
inny niepowtarzalny numer PESEL, nie zachodzi obawa, że może on się powtórzyć. Taką kolumnę
(atrybut) nazywamy kluczem Głównym (primary key).
<br/>
**Rodzake kluczy**
- **klucz prosty** – to taki, który jest jednoelementowy (składa się z jednej kolumny),
- **klucz złożony** – to taki, który jest kilkuelementowy (składa się z więcej niż jednej
kolumny).
Kluczem może być zatem jedna lub kilka kolumn, które wspólnie będą w stanie jednoznacznie
zidentyfikować pozostałe dane w tabeli (relacji). Kolumny, które należą do kluczy (używa się ich
do jednoznacznej identyfikacji wierszy w tabeli), nazywamy atrybutami podstawowymi.
Kolumny nie należące do kluczy (zawierają dane, które w określonej relacji są przedmiotem opisu)
nazywamy atrybutami opisowymi.
Do łączenia dwóch tabel (np. A i B) za pomocą związków używa się klucza. Klucz pochodzący z
obcej tabeli B (w której jest on kluczem głównym), używany do łączenia tej tabeli z tabelą A,
będzie dla tabeli A kluczem obcym.
**Superklucz** (superkey) – to kolumna lub zestaw kolumn jednoznacznie identyfikujących każda
krotkę tabeli. Super klucz może zawierać kolumny, które samodzielnie mogą nie identyfikować
każdej z krotek. Unikatowa identyfikacja każdej z krotek może odbywać się jedynie przez zestaw
np. dwóch lub trzech atrybutów. Przedmiotem zainteresowań projektantów baz danych jest taki
superklucz, który zawiera minimalny zestaw atrybutów unikatowo identyfikujących krotkę.
**Klucz kandydujący** (nadklucz, klucz potencjalny) o super klucz zawierający minimalną liczbę
kolumn unikatowo identyfikujących krotki relacji. W praktyce to kolumna lub kolumny, których
użycie w charakterze klucza głównego jest rozważane przez projektanta baz danych. To właśnie
twórca bazy danych decyduje, której kolumnie (kolumnom) nada funkcję klucza głównego.
**Klucz główny** (primary key) to klucz, który został wybrany, aby unikatowo identyfikować krotki
tabeli. Klucz główny jest podyktowany wyborem projektanta bazy danych.
h
<br/>
## 29. Spójność referencyjna baz danych.
**Spójność referencyjna** baz danych polega na wprowadzeniu i utrzymaniu powiązań pomiędzy tabelami.
To zespół reguł, które gwarantują logiczną spójność danych wprowadzanych i przechowywanych w bazie.
Zadaniem więzów spójności jest zagwarantowanie tego, aby dane w bazie danych wiernie odzwierciedlały świat
rzeczywisty, dla opisu którego baza danych została zaprojektowana. Więzy spójności definiowane są na etapie
projektowania bazy danych, tworzone wraz z innymi obiektami, przy tworzeniu bazy.
Wyróżniamy dwa typy więzów spójności:
- **Spójność encji** - ograniczają możliwe wartości, jakie mogą się pojawić w wierszu tabeli:
- **Więzy klucza głównego PRIMARY KEY** – wartości w określonych kolumnach jednoznacznie identyfikują wiersz tabeli. W kolumnach klucza głównego nie jest dozwolona pseudo-wartość NULL . Automatycznie jest zakładany indeks na kolumnach tworzących klucz główny. Może być określony tylko jeden klucz główny dla jednej tabeli.
- **Więzy klucza jednoznacznego UNIQUE** – wartości w określonych kolumnach jednoznacznie identyfikują wiersz tabeli. W kolumnach klucza jednoznacznego jest dozwolona pseudo-wartość NULL . Automatycznie jest zakładany indeks na kolumnach tworzących klucz jednoznaczny. Może być określony więcej niż jeden klucz jednoznaczny dla jednej tabeli.
- **Więzy NOT NULL** – w kolumnie nie jest dozwolona pseudo-wartość NULL.
- **Więzy CHECK** – warunek, który ma być prawdziwy dla wszystkich wierszy w tabeli. Nie może zawierać podzapytania ani funkcji zmiennych w czasie, jak Sysdate lub User. Może zawierać nazwy jednej lub więcej kolumn.
- **Spójność referencyjna** - zapewniają, że zbiór wartości w kolumnach klucza obcego jest zawsze podzbiorem zbioru wartości odpowiadającego mu klucza głównego lub jednoznacznego. Ponieważ wartości klucza głównego lub jednoznacznego jednoznacznie określają obiekty, więc klucz obcy wskazuje zawsze na istniejący obiekt. Wartością klucza obcego może też być NULL – wówczas klucz obcy nie wskazuje na żaden obiekt. System zapewnia, aby obiekt wskazywany przez wartość klucza obcego zawsze istniał, niezależnie od wszystkich możliwych operacji na tabelach, w których biorą udział klucze główne, jednoznaczne i obce.
<br/>
## 30. Normalizacja relacji - postaci normalne.
**Normalizacja baz danych** - proces w ramach którego doprowadzamy bazę danych do postaci
normalnych. W przypadku gdy baza danych nie jest znormalizowana występuje redundancja danych.
Redundancja danych w najprostszym wytłumaczeniem jest sytuacją gdy dane się powtarzają np. są zdublowane.
<br/>
**Pierwsza postać normalna** - występuje gdy każda kolumna jest atomowa tzn. nie zawiera list
i dane są niepodzielne.

Przedstawiona tabela nie spełnia pierwszej postaci normalnej (1NF) ponieważ kolumna Adres nie jest atomowa. Możemy ją
podzielić na pojedyncze kolumny. Aby więc doprowadzić naszą tabelę do 1NF należy kolumnę adres podzielić na kilka
pojedynczych kolumn. Poniższa tabela została tak zmieniona, że spełnia 1NF:

<br/>
**Druga postać normalna** - baza danych jest w drugiej postaci normalnej gdy spełnia pierwszą postać normalną oraz wszystkie kolumny w tabeli zależą
tylko od klucza.
Czy powyższa baza jest w 2NF? Nie ponieważ jak się zastanowić to z tabeli możemy wyodrębnić przynajmniej trzy zbiory danych zależne od różnych kluczy: KLIENT, PIZZA, ZAMÓWIENIE.

Powyższa baza została sprowadzona do drugiej postaci normalnej.
<br/>
**Trzecia postać normalna** - Baza jest w trzeciej postaci normalnej wtedy gdy spełnia drugą postać normalną oraz żadna z kolumn nie jest zależna od innej kolumny która nie jest kluczem.
Tabela KLIENT spełnia 3NF natomiast tabela PIZZA jej nie spełnia ponieważ kolumna CENA nie jest zależna od klucza
a od wielkośc i pizzy. Aby to zmienić należy dane dotyczące cen wyciągnąć do inny tabeli jak na poniższym schemacie:

<br/>
**Kolejne postacie normalne**
W bazach danych występują jeszcze inne postaci normalne jak: Byce-Codde, 4NF, 5NF. Kolejne postaci normalne mówią, że naszą bazę można jeszcze bardziej podzielić. Dla przykładu miasto nie jest bezpośrednio związane z adresem a z ulicą na którą zamawiamy dlatego też ulicę można by wyciągnąć do osobnej tabeli.## 31. Modelowanie bazy danych - rodzaje połączeń relacyjnych, pojęcie klucza głównego i obcego.
<a href="<link_to_resource_local_or_)nline_here>"></a><b></b>
**Klucz potencjalny** - minimalny zestaw atrybutów relacji, jednoznacznie identyfikujący każdą krotkę tej relacji. W relacji
może znajdować się wiele kluczy potencjalnych (zwanych czasem **kandydującymi**). Spośród kluczy potencjalnych
wybiera się zazwyczaj jeden klucz, zwany kluczem głównym.
**Klucz główny** (primary key) – wybrany minimalny zestaw atrybutów relacji, jednoznacznie identyfikujący każdy rekord
tej relacji. To oznacza, że taki klucz musi przyjmować **wyłącznie** wartości niepowtarzalne i nie może być wartością
pustą (null). Ponadto każda relacja może mieć najwyżej **jeden** klucz główny.<br>
Kluczem głównym może być dowolny klucz potencjalny, ale często stosuje się rozwiązanie polegające na utworzeniu
specjalnego atrybutu, którego wartości domyślne pobierane są z sekwencji (tzw. autonumeracja), tak aby zapewnić
unikalność klucza.
**Klucz obcy** - kombinacja jednego lub wielu atrybutów tabeli, które wyrażają się w dwóch lub większej liczbie relacji
(tabel). Wykorzystuje się go do tworzenia powiązania pomiędzy parą tabel, gdzie w jednej tabeli ten zbiór atrybutów jest
kluczem obcym, a w drugiej kluczem głównym.
### Związek 1:1 (jeden do jednego)

### Relacja 1:N (jeden do wielu)

### Relacja N:N (wiele do wielu)

## 32. Pojęcie indeksu - rodzaje i zastosowanie.
Indeksowanie jest podstawowym mechanizmem wykorzystywanym w celu optymalizacji baz
danych SQL. Gdyby porównać bazę danych do książki, indeksy są czymś w rodzaju spisu treści.
Z technicznego punktu widzenia (i mocno uogólniając) indeksy to zbiór wartości typu „klucz –
lokalizacja”. Dzięki temu, na podstawie konkretnego klucza czyli parametrów zapytania jest
możliwe bardzo szybkie zwrócenie odpowiednich danych.
Klucze w indeksie przechowywane są w strukturze zwanej B-Tree (nie należy mylić tej
struktury danych z drzewem binarnym). B-Tree pozwala mechanizmom SQL Server znaleźć
pożądany rekord szybciej i wydajniej, ale tylko wtedy, gdy wyszukiwanie w tym drzewie
odbywa się za pomocą klucza.
B-drzewo i Drzewo binarne to typy nieliniowej struktury danych. Chociaż warunki wydają się
być podobne, ale różnią się pod każdym względem.
Drzewo binarne jest używane, gdy rekordy lub dane są przechowywane w pamięci RAM zamiast
na dysku, ponieważ prędkość dostępu do pamięci RAM jest znacznie większa niż na dysku. Z
drugiej strony B-tree jest używane, gdy dane są przechowywane na dysku, skraca czas dostępu,
zmniejszając wysokość drzewa i zwiększając gałęzie w węźle.

Problem z przeszukiwaniem baz danych polega na tym, że tabele nie są posortowane. Jedyna „kolejność” to często klucz
główny PRIMARY_KEY. Nie jest to przydatna kolejność kiedy szukamy danych nie po kluczu a po jakimś innym polu np:
SELECT nazwa_produktu FROM produkty WHERE cena = 128;
W przypadku kiedy dane są posortowane po kluczu głównym trzeba „sprawdzić” wszystkie rekordy i nie mamy
możliwości ułatwienia sobie zadania bo produkty mogą mieć przecież różną cenę. Mówi wtedy że dokonujemy pełnego
skanu tabeli, który działa niekorzystnie na wydajność. Indeksowania polega na unikaniu tego pełnego skanu.
### Jak działają indeksy?
Indeks jest uporządkowanym plikiem rekordów indeksu o stałej długości. Rekordy indeksu zawierają dwa pola: klucz
reprezentujący jedną z wartości występujących w atrybutach indeksowych relacji oraz wskaźnik do bloku danych
zawierający krotkę, której atrybut indeksowy równy jest kluczowi.
### Jak np.MySQL używa indeksów
- szybko znajduje wiersze pasujące do klauzuli
- ignoruje pewne wiersze (jeżeli MySQL ma do dyspozycji wiele indeksów używa tego najmniejszego) co przyspiesza skanowanie,
- szybciej zwraca zapytania w przypadku złączania wielu tabel,
- szybciej zwraca zapytania MIN() i MAX()
### Jakie kolumny i tabele należy indeksować
Korzyść wydajnościowa ze stosowania indeksów jest największa w przypadku dużych tabel (zawierających najwięcej
rekordów) oraz zapytań, które wykonywane są najczęściej.
W MySQL zaleca się indeksować następujące kolumny:
-kolumny najczęściej padające po słowie WHERE,
- kolumny dwóch tabel, które często łączymy,
- kolumny, według których sortujemy dane w raportach (kolumny padające po słowie ORDER BY i GROUP BY),
- kolumny które często zliczamy (SUM(), AVG(), MIN(), MAX(), COUNT())
- klucze obce i kolumny, których będziemy używać tak jak kluczy obcych,
- klucze niepowtarzalne UNIQUE_KEY (typu NIP, PESEL itd...),
### Nadmiar indeksów
Należy pamiętać, że indeks drastycznie **spowalnia dodawanie, modyfikowanie i usuwanie danych**, ponieważ indeksy muszą
być aktualizowane za każdym razem, gdy tabela ulega nawet najmniejszej modyfikacji. Najlepszą praktyką jest dodanie
indeksu dla wartości, które są **często używane do wyszukiwania, ale nie ulegają częstym zmianom.**
### Rodzaje indeksów
- Indeks pogrupowany (clustered)
W jednej tabeli możemy posiadać tylko jeden index klastrowany dla jednej lub wielu kolumn. Założenie takiego indexu
równa się fizycznemu posortowaniu danych na dysku, w związku z tym niemożliwe jest założenie dwóch tego rodzaju
indexów.
Odczyt danych z tabeli która nie jest jest posortowana w przypadku gdy posiada setki tysięcy bądź miliony rekordów jest
bardzo czasochłonne. Serwer bazodanowy musi przejść rekord po rekordzie, by zwrócić dane o które prosimy. W związku z
tym należy założyć index, na przynajmniej jedną kolumnę aby usprawnić proces ‚poszukiwania’ rekordów.
> **CREATE CLUSTERED INDEX** nazwaIndeksu **ON** nazwaTabeli(nazwaKolumny);
Index klastrowany może być tylko jeden, ale może zostać założony na więcej niż jedną kolumnę
> **CREATE CLUSTERED INDEX** IX_EmployeesAgeFullName **ON** Employees(Age,FullName);
Nasza tabela została posortowana najpierw po kolumnie Age a następnie po kolumnie FullName
<br><br>
- Indeks niepogrupowany (non clustered)
Są swego rodzaju kopią danych, kopią kolumny na którą został założony taki index. Możemy posiadać więcej niż jeden index
non-clustred, jednak warto wiedzieć, że podczas zapisu danych do tabeli, jeśli dane wymagają ponownego posortowania, to
operacja zapisu będzię trwać dłużej. Im więcej indexów, tym dłuższy czas oczekiwania na ukończenie operacji. Tego typu
index jest również wolniejszy jeżeli odpytujemy o więcej danych, niż zostało to zadeklarowane na początku.
> **CREATE NONCLUSTERED INDEX** nazwaIndexu **ON** nazwaTablicy(nazwaKolumny);
## 33. Podstawowe konstrukcje języka SQL.
### Cechy języka SQL
- Język wysokiego poziomu
- Jest językiem deklaratywnym, zorientowanym na wynik
- Jest oparty na algebrze relacji
- Zawiera logikę trójwartościową
- Nie posiada instrukcji sterujących wykonywaniem programu
- Nie dopuszcza rekurencji
- Umożliwia definiowanie struktur danych, wyszukiwanie danych oraz operacje na danych
- Działa na zbiorach danych
### Struktura i wykorzystanie języka SQL
- Język SQL jest przykładem języka transformacji, co oznacza, że został on tak zaprojektowany, że
umożliwia przekształcenie relacji wejściowych na relację wyjściową.
- Jest językiem nieproceduralnym, w którym użytkownik opisuje informację, której potrzebuje, ale nie
wskazuje on przy tym, w jaki sposób należy ją odnaleźć.
- Zapytanie języka SQL składa się ze słów zarezerwowanych oraz ze słów zdefiniowanych przez samego
użytkownika. Należy je zapisywać w sposóbdokładny, bez jakichkolwiek zmian, tj. dokładnie tak jak
wymaga tego składnia języka SQL.
- Każde zapytanie w języku SQL jest kończone średnikiem.
### Komponenty języka SQL
- **DDL (Data Definition Language)** – język definiowania struktur danych
(CREATE, DROP, ALTER TABLE).
- **DML (Data Manipulation Language)** – język operacji na danych (SELECT, INSERT, UPDATE, DELETE).
- **Instrukcje sterowania danymi** – kontrola uprawnień użytkowników (GRANT, REVOKE).
### Tabele w języku SQL
Do manipulowania tabelkami używa się kilku poleceń:
- **CREATE TABLE** – definiuje tabelę i jej kolumny,
- **ALTER TABLE** – zmienia tabele i kolumny,
- **DROP TABLE** – usuwa tabelę – jej definicję i zawartość,
- **RENAME** – zmienia nazwę tabeli
Polecenia **CREATE TABLE** i **ALTER TABLE** są ponadto używane w celu definiowania ograniczeń kluczy oraz
tzw. parametrów przechowywania, które są rozszerzeniami składni Oracle.
### Typy danych // Typy tekstowe
- **VARCHAR2(L)** – oznacza typ danych, za pomocą którego można przechowywać ciągi znaków o
zmiennej długości, gdzie L oznacza określoną maksymalną długość zmiennej tego typu. Dopuszczalny
rozmiar dla zmiennej VARCHAR2 wynosi 4000 bajtów.
- **VARCHAR(L)** – pozwala przechowywać napisy o zmiennej długości, których długość może wahać się
od 1 do 2000 znaków.
- **CHAR(L)** – pozwala przechowywać ciągi znaków o stałej długości wskazanej w parametrze rozmiar.
Maksymalna wielkość to 2000 bajtów. Długość domyślna to 1 znak. Ciągi są dopełniane z prawej strony
spacjami do pełnej wielkości pola.
### Typy numeryczne
- **NUMBER(zakres)** – typ całkowity – pozwala przechowywać liczby całkowite ze znakiem mającą tyle
cyfr, ile wynosi parametr zakres (o maksymalnej długości 38 cyfr).
- **NUMBER(zakres, dokładność)** – określa dziesiętną liczbę stałoprzecinkową zapisywaną z dokładnością
do maksymalnie 38 cyfr i wykładnikiem pomiędzy -84 a 127.
- **NUMBER** – określa kolumnę zmiennoprzecinkową z 38 cyframi pamiętanymi dokładnie i wykładnikiem
pomiędzy 125 a -127.
### Typ czasu
- **DATE** – obejmuje okres od pierwszego stycznia 4712 r. p.n.e. do 31 grudnia 4712 r. n.e.
<br> Kolumna typu
DATE może przechowywać czas z dokładnością do sekund.
### Operacje DDL
Tworzenie nowej tabeli
**CREATE TABLE** *nazwa_tabeli (nazwa_kolumny1 typ_danych1)*;
``` CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15),
cena NUMBER(7,2),
kategoria VARCHAR2(30),
stan_magazyn NUMBER,
wycofany CHAR(3) );
CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15),
cena NUMBER(7,2),
kategoria VARCHAR2(30),
stan_magazyn NUMBER,
wycofany CHAR(3) );
Tabele i ich zawartość są usuwane za pomocą polecenia DROP TABLE nazwa_tabeli. Dla tabel, do których nie odwołuje się żaden klucz obcy, tabela i jej zawartość zostanie całkowicie usunięta.
Przykład: DROP TABLE czytelnicy CASCADE CONSTRAINTS;
Przykład: TRUNCATE TABLE towary;
Z pewnymi ograniczeniami, przy użyciu opcji MODIFY polecenia ALTER TABLE można zmienić cztery części definicji kolumny:
Przykład: ALTER TABLE towary MODIFY (kategoria VARCHAR(30) NOT NULL);
Usunięcie kolumny z tabeli:
Przykład: ALTER TABLE nazwa_tabeli DROP COLUMN nazwa_kolumny;
Ograniczenia, jakie można ustawić dla tabel/kolumn służą następującym celom:
Ograniczenia mogą być:
Istnieje kilka możliwości wykorzystania ograniczenia CHECK:
Ograniczenie CHECK jest definiowane:
Przykład:
CREATE TABLE drużyny_pilkarskie (
nr_druzyny NUMBER(4) NOT NULL,
nazwa VARCHAR2(30) NOT NULL,
liczba_goli NUMBER NOT NULL,
liczba_goli_dom NUMBER CHECK(liczba_goli_dom <= liczba_goli), liczba_goli_wyjazd
NUMBER CHECK(liczba_goli_wyjazd <= liczba_goli) );
Nazywanie ograniczeń Jeśli w tabeli wprowadzamy ograniczenia bez podawania ich nazw, wówczas system sam nadaje każdemu ograniczeniu unikalną nazwę, która jest przechowywana w przestrzeni nazw.
Dla przykładu utwórzmy tabelę towary nazywając ograniczenia:
CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15) CONSTRAINT nazwa_nn NOT NULL,
cena NUMBER(7,2) CONSTRAINT cena_nn NOT NULL,
kategoria VARCHAR2(30) CONSTRAINT kategoria_nn NOT NULL, stan_magazyn
NUMBER DEFAULT 0,
wycofany CHAR(3) DEFAULT ‘Nie’,
CONSTRAINT towary_pk PRIMARY KEY(nr_towar),
CONSTRAINT wycofany_CH CHECK(wycofany IN ('Tak', 'Nie')));
W języku SQL poleceniami służącymi do modyfikowania danych w tabelach są jedynie trzy operacje, które zaliczamy do operacji DML:
Za pomocą polecenia INSERT można:
Składnia:
Przykład:
INSERT INTO towary (nr_towar, nazwa, cena, nazwa_kategorii, stan magazynu) VALUES (104, 'chleb', 2.20, 'pieczywo',100);
Składnia DELETE:
DELETE FROM nazwa_tabeli WHERE warunek_logiczny;
Przykład:
DELETE FROM towarywycofane
WHERE nr_towar IN (SELECT nr_towar
FROM towary WHERE stan = 0);
Polecenie TRUNCATE TABLE nazwa_tabeli przyśpiesza proces usuwania dzięki temu, że nie zapisuje informacji sprzed modyfikacji do przestrzeni wycofania. Ten fakt powoduje jednak, iż nie jest możliwe przywrócenie usuniętych danych. To polecenie nie zawiera także klauzuli WHERE, a zatem zawsze usuwa wszystkie wiersze wskazanej tabeli.
Polecenie UPDATE dotyczące aktualizacji danych różni się od pozostałych dwóch operacji DML dotyczących modyfikacji danych w tabelach, ponieważ nie ma wpływu na liczbę wierszy w tabeli.
Składnia:
UPDATE nazwa_tabeli
SET lista
WHERE warunek;
gdzie:
Polecenie UPDATE - przykład
UPDATE towary SET nazwa = ‘czekolada mleczna’, cena = 2.50 WHERE nr_towar = 1;
Podstawową, najczęściej używaną instrukcją języka SQL jest instrukcja SELECT, która służy do pobierania danych z jednej tabeli lub większej liczby tabel (widoków). Niezależnie od liczby tabel i/lub widoków oraz niezależnie od rodzaju operacji wykonywanych na zbiorach lub pseudozbiorach, zawsze jako wynik otrzymujemy wirtualną pojedynczą tabelę (tzw. dynamiczny zestaw wyników), którą dalej możemy przetwarzać.
Składnia:
SELECT lista_kolumn FROM lista_tabel;
Pobranie wszystkich wierszy i wszystkich kolumn:
SELECT * FROM towary;
Pobieranie wszystkich wierszy i wybranych kolumn:
SELECT nazwa, cena FROM towary;
W języku SQL listy przecinkowe są wykorzystywane w różnych celach:
Istotna odmiana listy przecinkowej powstaje w wyniku tzw. aliasingu, czyli nadawania aliasów („pseudonimów”) dla tych elementów, które bezpośrednio poprzedzają alias. Jeśli alias jest umieszczony za określanym elementem, to do tego elementu można odwołać się zarówno poprzez jego nazwę lub alias (poza pewnymi przypadkami, kiedy można odwołać się tylko za pomocą nazwy oraz pewnymi przypadkami, kiedy można odwołać się tylko za pomocą aliasu).
Przykład (nadanie zastępczych aliasów dwóm wyświetlanym kolumnom):
SELECT nazwa nazwa_towaru, cena cena_jednostkowa
FROM towary;
Klauzula ORDER BY instrukcji SELECT służy do sortowania danych w języku SQL. Sortowanie danych można wykonać na dwa sposoby: albo w porządku rosnącym (ustawienie domyślne) – opcja ASC lub w porządku malejącym wartości kolumny użytej do sortowania – opcja DESC.
Przykład:
SELECT nr_towar, nazwa, cena, stan, towary
FROM towary
ORDER BY cena DESC;
Zanim dane z urządzenia źródłowego zostaną przesłane do urządzenia końcowego muszą przejść długą drogę, podczas której najpierw są odpowiednio oznaczane, tagowane, opisywane określonymi informacjami pozwalającymi na ich identyfikację, potem przesyłane są pomiędzy wieloma urządzeniami pośredniczącymi, aż trafią do odbiorcy, który dane to potem musi zinterpretować.
Gdyby nie istniał taki model, który dzieli komunikację na mniejsze, łatwiejsze do zrozumienia i zarządzania etapy oraz określa zadania, jakie muszą być realizowane w poszczególnych warstwach trudno byłoby we właściwy sposób zarządzać komunikacją sieciową ponieważ mnogość rozwiązań i technologii powodowałaby olbrzymi chaos, trudny do opanowania.
Warstwa 7: aplikacji - Udostępnia użytkownikom możliwość korzystania z usług sieciowych, takich jak WWW, poczta elektroniczna, wymiana plików, połączenia terminalowe czy komunikatory.
Warstwa 6: prezentacji - Przekazuje do warstwy aplikacji informacje o zastosowanym formacie danych, np. informuje jakie typy plików będą przesyłane, odpowiada ona również za odpowiednie zakodowanie danych na urządzeniu źródłowym i ich dekodowanie na urządzeniu docelowym.
Warstwa 5: sesji - Warstwa sesji otrzymuje od różnych aplikacji dane, które muszą zostać odpowiednio zsynchronizowane. Synchronizacja występuje między warstwami sesji systemu nadawcy i odbiorcy. Warstwa sesji „wie”, która aplikacja łączy się z którą, dzięki czemu może zapewnić właściwy kierunek przepływu danych –nadzoruje połączenie. Wznawia je po przerwaniu.
Warstwa 4: transportu - Głównym zadaniem jest sprawna obsługa komunikacji pomiędzy urządzeniami. W warstwie tej dane dzielone są na mniejsze części, następnie opatrywane są dodatkowymi informacjami pozwalającymi zarówno przydzielić je do właściwej aplikacji na urządzeniu docelowym, jak i pozwalającymi złożyć je na urządzeniu docelowym w odpowiedniej kolejności.
Warstwa 3: sieci - Warstwa sieciowa jako jedyna dysponuje wiedzą dotyczącą fizycznej topologii sieci. Rozpoznaje, jakie drogi łączą poszczególne komputery (trasowanie) i decyduje, ile informacji należy przesłać jednym z połączeń, a ile innym. Jeżeli danych do przesłania jest zbyt wiele, to warstwa sieciowa po prostu je ignoruje.
Warstwa 2: łącza danych - Głównym zadaniem jest kontrola dostępu do medium transmisyjnego, a także adresowanie danych, tym razem jednak w celu przesyłania ich pomiędzy hostami w sieci LAN.
Warstwa 1: fizyczna - Koduje dane do postaci czystych bitów (zer i jedynek) i przesyła je poprzez medium transmisyjne do odpowiednich urządzeń.


TCP/IP (ang. Transmission Control Protocol/Internet Protocol) to zbiór protokołów służących do transmisji danych przez sieci komputerowe. Model TCP/IP został stworzony w latach 70. XX wieku w DARPA, aby pomóc w tworzeniu odpornych na atak sieci komputerowych. Potem stał się podstawą struktury Internetu. Model TCP/IP implementuje najważniejsze funkcjonalności siedmiu warstw standardowego modelu OSI. Poniższy schemat przedstawia odpowiadające sobie warstwy modeli TCP/IP i OSI.

Każda wiadomość wysłana przez aplikację przechodzi przez wszystkie warstwy TCP/IP, od warstwy aplikacji do najniższej warstwy dostępu do sieci. Następnie jest transmitowana przez sieć do drugiego komputera. Na koniec przechodzi przez wszystkie warstwy w przeciwnym kierunku, aż do warstwy aplikacji i docelowego procesu. Podczas przesyłania danych z aplikacji do sieci, każda warstwa dodaje swój własny nagłówek do każdej wiadomości. Każdy z tych nagłówków jest potem odczytywany przez odpowiednią warstwę w komputerze odbierającym wiadomość. Zarówno zawartość jak i wielkość nagłówków zależą od użytych protokołów.


Pośredniczy w komunikacji pomiędzy programami komputerowymi i protokołami niższych warstw, umożliwiając w ten sposób aplikacjom korzystanie z sieci. Jest to warstwa najbliższa użytkownikowi, ponieważ to właśnie ona pozwala nam w pełni korzystać z usług sieciowych. Kiedy siadamy przed komputerem i uruchamiamy np. przeglądarkę internetową to korzystamy z sieci właśnie na poziomie warstwy aplikacji. Istnieje wiele protokołów warstwy aplikacji, które wykorzystują transmisję TCP/IP.
Budowa wiadomości warstwy aplikacji różni się w zależności od protokołu, który został użyty. Każdy protokół może wymagać różnych danych wejściowych i produkować różne zapytania, które będą wysłane do warstwy transportowej. Niezależnie od formy wiadomości utworzonej przez warstwę aplikacji, warstwa transportowa traktuje każdą otrzymaną wiadomość jako dane i nie wnika w ich zawartość.
Gniazda sieciowe to struktury, które są wykorzystywane podczas komunikacji pomiędzy warstwami aplikacji i transportową. Każdy proces i aplikacja, który próbuje połączyć się z siecią, musi powiązać swoje kanały transmisji danych wejściowych i wyjściowych poprzez utworzenie właściwego obiektu gniazda sieciowego.
Obiekt gniazda sieciowego zawiera informacje o adresie IP, numerze portu i użytym protokole warstwy transportowej. Unikalna kombinacja tych trzech parametrów pozwala na zidentyfikowanie właściwego procesu, do którego wiadomość powinna być dostarczona.
Numer portu może zostać przypisany automatycznie przez system operacyjny, ręcznie przez użytkownika lub może być mu przypisana wartość domyślna, właściwa pewnym popularnym aplikacjom. Numer portu jest 16-bitową liczbą całkowitą (0 - 65535).
Niektóre popularne protokoły warstwy aplikacji używają domyślnych i publicznie znanych numerów porów. Na przykład, HTTP używa portu 80, HTTPS używa portu 443, SMTP portu 25, Telnet portu 23, natomiast FTP używa dwóch portów: 20 do transmisji danych i 21 kontroli transmisji. Lista domyślnych numerów portów jest zarządzana przez organizację Internet Assigned Numbers Authority.
Jej głównym zadaniem jest sprawna obsługa komunikacji pomiędzy urządzeniami. W warstwie tej dane dzielone są na mniejsze części, następnie opatrywane są dodatkowymi informacjami (nagłówki) pozwalającymi zarówno przydzielić je do właściwej aplikacji na urządzeniu docelowym, jak i pozwalającymi złożyć je na urządzeniu docelowym w odpowiedniej kolejności. Nagłówek zawiera szereg informacji kontrolnych, w szczególności numery portów nadawcy i odbiorcy.
Najpopularniejszym protokołem warstwy transportowej jest TCP (ang. Transmission Control Protocol). Podczas transmisji danych, TCP zestawia połączenie pomiędzy komunikującymi się stronami przez zainicjowanie tzw. sesji (ang. session). TCP jest protokołem niezawodnym, w którym odbiorca potwierdza otrzymanie każdej wiadomości. Wszystkie wiadomości dostarczane są w takiej samej kolejności, w jakiej zostały wysłane. Wszystkie cechy wymienione powyżej są zapewniane przez warstwę TCP. Oznacza to, że TCP może współdziałać z innymi, bardziej zawodnymi protokołami niższych warstw i nie powinno to afektować komunikacji z perspektywy warstwy aplikacji.
Odbiorca testuje każdy otrzymany pakiet pod kątem błędów transmisji (poprzez wyliczanie sumy kontrolnej danych). Jeśli wiadomość jest poprawna, odbiorca wysyła potwierdzenie do nadawcy. Jeśli nadawca nie otrzyma potwierdzenia w przeciągu określonego (konfigurowalnego) czasu, to ponownie wysyła zagubiony pakiet. Po kilku nieudanych próbach, TCP zakłada, że odbiorca jest nieosiągalny i informuje warstwę aplikacji, że transmisja zakończyła się niepowodzeniem.
Jedno z pól nagłówka TCP zawiera numer sekwencyjny wiadomości. Numer sekwencyjny jest zwiększany o jeden dla każdej wysłanej wiadomości. Podczas odbierania wiadomości, TCP układa pakiety we właściwej kolejności. Dzięki temu, warstwa aplikacji nie musi w ogóle zajmować się kolejnością przychodzących pakietów sieciowych.
Składa się z 20 lub więcej bajtów. Dokładna wielkość zależy od tego czy opcjonalne pole opcji jest używane. Maksymalna wielkość tego pola to 40 bajtów, więc maksymalna wielkość całego nagłówka to 60 bajtów.

W celu wymiany danych przy pomocy TCP, dwie aplikacje muszą najpierw
zainicjować sesję.
TCP wymaga wymiany trzech wiadomości żeby utworzyć sesję:
Kiedy transmisja pomiędzy klientem i serwerem zostanie zakończona, sesja powinna zostać zamknięta. Każda strona komunikacji może zakończyć trwającą sesję. Druga strona powinna odpowiedzieć na to, wysyłając odpowiednie potwierdzenie.
Zastosowanie TCP. TCP jest szeroko wykorzystywane w protokołach i aplikacjach, które wymagają wysokiej niezawodności. Można wymienić wiele protokołów warstwy aplikacji, które używane są głównie razem z TCP.
Jednymi z najpopularniejszych są:
Drugim popularnym protokołem używanym w warstwie transportowej jest UDP (ang. User Datagram Protocol lub Universal Datagram Protocol). Jest to prostszy protokół, w którym komunikacja odbywa się bez nawiązywania żadnego stałego połączenia pomiędzy aplikacjami. Wszystkie pakiety wysyłane są niezależnie od siebie. Dzięki swojej prostocie UDP jest szybsze niż TCP. Z drugiej jednak strony, nie zapewnia takiej niezawodności działania jak TCP, nie gwarantuje, że wiadomości rzeczywiście dotarły do odbiorcy. UDP nie dostarcza pakietów w takiej samej kolejności, w jakiej zostały one wysłane. Ciężar uporządkowania otrzymywanych wiadomości i sprawdzenia czy nie nastąpiły błędy transmisji spoczywa na otrzymującej je aplikacji.
Składa się z 8 bajtów, jest więc znacznie krótszy niż odpowiadający mu nagłówek TCP.

UDP jest preferowane jeśli przesyłane pakiety danych są nieistotne lub komunikacja musi odbywać się z wyjątkowo dużą prędkością czyli np. podczas transmisji audio i video, gdzie utrata pewnej liczby pakietów nie jest bardzo uciążliwa dla odbiorcy. Istnieje wiele protokołów warstwy aplikacji, które używają UDP, na przykład:
Datagram Congestion Control Protocol jest protokołem, który umożliwia aplikacjom
kontrolowanie przepływu danych w celu zapobiegania przeciążeniom sieci i utrzymywania
stabilnych połączeń. DCCP nie zapewnia niezawodnej komunikacji z zachowaniem kolejności
wysyłanych pakietów.
DCCP jest wykorzystywany przez aplikacje, które operują na szybko zmieniających się
danych (dane audio i video, gry online, VoIP). W takich sytuacjach często preferuje się użycie
nowej porcji dostępnych danych, zamiast proszenia o retransmitowanie starego
uszkodzonego pakietu.
Resource Reservation Protocol umożliwia zdalne rezerwowanie zasobów przy użyciu sieci
komputerowych. Jest używany głównie przez routery i serwery w celu zapewnienia usług
o określonej jakości dla klientów.
RSVP jest w stanie rezerwować pasma transmisji dla komunikacji pomiędzy dwoma
komputerami oraz pomiędzy jednym serwerem i wieloma klientami. Wymiana wiadomości w
ramach RSVP jest inicjowana przez klienta (odbiorcę), który prosi router (serwer)
o zarezerwowanie zasobów.
Stream Control Transmission Protocol umożliwia przesyłanie wielu strumieni danych
spakowanych razem w pojedynczym strumieniu. Podobnie jak TCP, SCTP zapewnia
niezawodną transmisję z zachowaniem kolejności pakietów i zapobieganiem przeciążeniom,
dodatkowo rozbudowując jego funkcjonalności o umieszczanie pokrewnych strumieni danych
w tych samych wiadomościach.
Ogólnie rzecz biorąc SCTP, jest bardzo rozbudowanym protokołem zapewniającym
dobrą jakość komunikacji. Niestety, z racji braku wspierania tego protokołu przez
najpopularniejsze routery i systemy operacyjne, nie jest on popularny i szerzej używany.
Głównym zadaniem jest odnalezienie najkrótszej i najszybszej drogi do urządzenia docelowego przez sieć rozległą, podobnie jak robią to samochodowe GPS’y, ale także adresowanie danych z wykorzystaniem adresów logicznych (adresów IP). Adres IP jest unikalnym wirtualnym numerem, który umożliwia znajdowanie urządzenia w sieci. Istnieje kilka popularnych protokołów, które działają w warstwie internetowej. Najpopularniejszym i najważniejszym z nich jest IP (Internet Protocol), ale warto wymienić też
Inne protokoły warstwy internetowej:
IP służy do przesyłania pakietów danych przez sieć. Obecnie używane są dwie wersje tego protokołu, IPv4 i IPv6.
IP nie zapewnia żadnego systemu potwierdzania dostarczenia wiadomości, co oznacza, że nie jest niezawodnym protokołem. Obowiązek upewniania się, że wszystkie dane zostały dostarczone spoczywa na protokole TCP operującym w warstwie transportowej. Całe połączenie TCP/IP jest więc niezawodne.
Pakiety danych otrzymywane z warstwy transportowej są dzielone na mniejsze datagramy.
Każdy datagram zawiera nagłówek IP oraz bajty otrzymane z warstwy transportowej.
Maksymalna wielkość datagramu zależy od wersji IP: 216−1 bajtów dla IPv4 oraz 232−1
dla IPv6. Jeśli pakiet otrzymany z warstwy transportowej jest zbyt duży, zostanie podzielony
na kilka datagramów o odpowiedniej wielkości.
Zwykle dane dzielone są na mniejsze datagramy niż wynikałoby to z ograniczeń protokołu IP.
Jest to spowodowane ograniczonymi możliwościami fizycznymi sieci komputerowych. Na
przykład, maksymalna wielkość ethernetowych pakietów wynosi 1 500 bajtów, więc zwykle
datagramy tworzone w warstwie internetowej operującej na ethernecie będą nieco mniejsze
niż 1 500 bajtów (aby umożliwić niższym warstwom dodanie swoich nagłówków).
Maksymalna wielkość datagramu w sieci jest nazywana MTU (Maximum Transfer Unit).
IP umożliwia dzielenie datagramów na mniejsze datagramy, jeśli przechodzą one przez sieć z
mniejszą wartością MTU. Kiedy mniejsze datagramy docierają znowu do sieci o większej
wartości MTU, mogą zostać ponownie zebrane do większego pakietu. W nagłówku IP jest
specjalne pole pozwalające na przeprowadzanie takich operacji (nazywające się Fragment Offset).
Umożliwia przesłanie datagramów z warstwy internetowej, przez fizyczną sieć do drugiego
komputera, gdzie są one przesyłane przez odpowiadającą jej warstwę dostępu do sieci do
warstwy internetowej, a następnie poprzez pozostałe warstwy do docelowej aplikacji.
Obecnie, większość komputerów jest podłączona do sieci ethernetowych, które mogą być
zarówno przewodowe jak i bezprzewodowe. Wobec tego protokoły TCP/IP wyższych warstw
najczęściej są używane razem z zestawem protokołów ethernetowych.
Istnieją trzy warstwy ethernetowe. Pierwsze dwie, Logic Link Control (LLC) i Media Access Control (MAC), odpowiadają warstwie łącza danych w modelu OSI. Trzecia, najniższa warstwa to warstwa fizyczna, podobnie jak w modelu OSI.

Jej najważniejszym zadaniem jest przekazanie informacji do docelowej maszyny odnośnie tego jaki protokół powinien być użyty w warstwie transportowej. Umożliwia to poprawne odczytanie przychodzącej wiadomości przez odbiorcę. Warstwa LLC dopisuje informacje o protokole użytym w warstwie internetowej i o protokole, który powinien otrzymać wiadomość. Pozwala to warstwie LLC na docelowym komputerze poprawnie dostarczyć otrzymane datagramy. Zdefiniowana przez standard IEEE 802.2.
jest odpowiedzialna za tworzenie końcowej wiadomości ethernetowej, która będzie wysłana przez sieć komputerową. Podobnie jak inne warstwy, warstwa MAC tworzy swój własny nagłówek i dodaje go do wiadomości. Nagłówek zawiera adresy MAC nadawcy i odbiorcy, czyli fizyczne adresy dwóch komunikujących się maszyn. Jeśli docelowa maszyna znajduje się za routerem, w innej sieci, to pole adresu odbiorcy będzie miało wartość adresu
routera. Adres MAC odbiorcy będzie zmieniony na inny przez router, kiedy będzie on przetwarzał wiadomość. Warstwa MAC dodaje również 4 kontrolne bajty CRC, które mogą być wykorzystane do naprawienia uszkodzonej wiadomości. Warstwa MAC dla sieci przewodowych jest zdefiniowana przez standard IEEE 802.3. Sieci bezprzewodowe są zdefiniowane przez IEEE 802.11. Warstwa Fizyczna Warstwa fizyczna jest odpowiedzialna za przekształcanie wiadomości w (zależności od typu sieci) impulsy elektryczne lub fale elektromagnetyczne oraz za transmitowanie ich przez sieć fizyczna pomiędzy komunikującymi się maszynami. Jest zdefiniowana przez te same specyfikacje co warstwa MAC, IEEE 802.3 i IEEE 802.11.
![]()
Cechy:
Cechy:
![]()
Cechy:
Cykl życia oprogramowania - Okres czasu rozpoczynający się kiedy pojawił się pomysł na oprogramowanie
Testowanie Oprogramowania - Jest to proces związany z wytwarzaniem oprogramowania. Jest on jednym z procesów kontroli jakości oprogramowania.
Podstawowym standardem dla testowania oprogramowania jest IEEE 829-1998 (829 Standard for Software Test Documentation).
Rodzaje testów:
Testy Manualne Testy wykonywane ręcznie przez testera, który przechodzi przez interfejs użytkownika zgodnie z określoną sekwencją kroków:
Testy dopasowane do aktualnego zapotrzebowania/przeznaczenia
Testy automatyczne Testy automatyczne skutecznie przyspieszają proces tworzenia testów systemowych, ich wykonywanie oraz analize, a tym samym pozwalają na wcześniejsze wykrycie i weliminowanie błędów w aplikacjach.
UML - Unified Modeling Language jest to język modelowy używany między innymi w inżynierii oprogramowania jako standardowy sposób wizualizacji projektu systemu.
Do kreacji UML przyczyniła się potrzeba standaryzacji różnych systemów wizualizacji systemów
rozwiazywania problemów. Został zaproponowany przez Rational software w połowie lat 90-
tych.
W 1997 UML został zaimplementowany przez Object Management Group jako główny system
organizacji, co było punktem przełomowym w popularyzacji języka.
W 2005 UML zostało zaadoptowane do standardu ISO (International Operation of
Standardization) i od tamtego czasu przechodzi okresowe rewizje, w 2020 roku wprowadzono
specyfikacje wersji 2.5.1
UML to sposób wizualizacji architektury systemów za pomocą diagramu. UML składa się ze standardowych elementów, które mają na celu przyspieszenie pracy. Diagram posiada sposoby wizualizacji miedzy innymi:
UML nie narzuca żadnego systemu pracy, ani żadnego systemu projektowania
oprogramowania. Jest jednak narzędziem, która wspomaga projektowanie tych systemów.
W programowaniu, bardzo dobrze sprawdza się jako sposób wizualizacji jak ma działać
program opierający się na obiektach.
Są różne systemy i UML stara się zaproponować wizualizacje każdego z nich za pomocą
różnych elementów, wyspecjalizowanych lub nie. Idea natomiast jest taka sama.
Diagram składa się z zawsze z wizualizacji danego obiektu, oraz interakcji między nimi.
Z takich standardowych przykładów używania UML możemy wymienić reprezentację systemu
za pomocą bramek logicznych.
UML 2 posiada wiele typów diagramów, które można podzielić na 2 typy :


Zespół projektowy jest to jednostka organizacyjna, powołana na zasadzie specjalizacji przedmiotowej, realizująca projekt pod bezpośrednim nadzorem kierownika projektu.
Grupa metod wytwarzania oprogramowania opartego na programowaniu iteracyjno-przyrostowym. Najważniejszym założeniem metodyk zwinnych jest obserwacja, że wymagania odbiorcy (klienta) często ewoluują podczas trwania projektu. Pojęcie zwinnego programowania zostało zaproponowane w 2001 w Manifeście Programowania Zwinnego.
„(...) Bardziej cenimy:
Ludzi i interakcje od procesów i narzędzi Działające
oprogramowanie od szczegółowej
dokumentacji
Współpracę z klientem od negocjacji umów
Reagowanie na zmiany od realizacji założonego planu.
Oznacza to, że elementy wypisane po prawej są wartościowe, ale większą wartość mają dla nas te, które wypisano po lewej.”
Są to iteracyjne i przyrostowe ramy postępowania zgodne ze Scrum Guide. Zgodnie z definicją ze Scrum Guide’a w obręb Scruma wchodzą: Zespoły Scrumowe oraz związane z nimi role, wydarzenia, artefakty i reguły.
ROLE: DEWELOPERZY + PRODUCT OWNER + SCRUM MASTER = ZESPÓŁ SCRUMOWY Deweloperzy, czyli zespół składający się z 3 9 osób z np.testera, analityka, webdewelopera, programisty dowolnego języka. Odpowiadają za sposób wykonania zadań. W zespole wszyscy powinni być równi. Product Owner odpowiada za wybór zadań do wykonania. Product Owner to osoba reprezentująca klienta , ciało jednoosobowe, jedyne, które może zlecać zadania zespołowi, dlatego bardzo ważne jest wsparcie jego roli w organizacji. Scrum Master czuwa nad tym, aby przebieg prac był zgodny z zasadami Scruma i ustalonymi przez zespół. Osoba ta odpowiedzialna jest za usuwanie wszelkich przeszkód uniemożliwiających zespołowi wykonanie zadania.
WYDARZENIA:
PLANOWANIE SPRINTU
CODZIENNY SCRUM +
PRZEGLĄD SPRINTU +
RETROSPEKTYWA =
SPRINT
ARTEFAKTY: BACKLOG PRODUKTU + BACKLOG SPRINTU + PRZYROST
Backlog Produktu to uporządkowana lista wszystkich rodzajów zadań potrzebnych do rozwoju, utrzymania i naprawy produktu.
Lista ta jest otwarta dla wszystkich w organizacji, natomiast Product Owner ma ostateczne słowo co do treści, wyglądu i
zawartości Backlogu. To jest jego narzędzie pracy nad produktem.
Backlog Sprintu to analogiczne narzędzie, ale dla Zespołu Deweloperskiego, który dzięki temu artefaktowi w pełni panuje nad
pracami zaplanowanymi na Sprint.
Przyrost to ukończona przez Zespół zgodnie z Definicją Ukończenia praca na koniec każdego i wszystkich razem Sprintów.
REGUŁY: PRZEJRZYSTOŚĆ + INSPEKCJA + ADAPTACJA
Przejrzystość zapewnia Zespowi Scrumowemu i wszystkim w organizacji dostęp do całości prac i takie samo rozumienie
każdego elementu Scruma. Dzięki temu nie ma niejasności i nieporozumień.
Inspekcja pozwala na bieżące monitorowanie i weryfikowanie przedmiotu pracy i sposobu pracy Zespołu.
Adaptacja powinna być wynikiem Inspekcji i prowadzić do niezbędnych zmian naprowadzających Zespół na właściwy tor
pracy.## 41. Pojęcie Maszyny Turinga - idea pracy automatu, hipoteza Churcha-Turinga
Maszyna Turinga - stworzona przez Alana Turinga prosta maszyna logiczna (licząca) służąca do wykonywania algorytmów. Wszystkie współczesne komputery dają się do niej sprowadzić. Problem jest rozwiązalny na komputerze, jeśli da się zdefiniować rozwiązującą go maszynę Turinga.
Maszyna Turinga zbudowana jest z trzech głównych elementów:
Taśma
Nieskończona taśma jest odpowiednikiem współczesnej pamięci komputera. Taśma dzieli się na komórki, w których umieszczone zostały znaki przetwarzane przez maszynę Turinga. Symbole te stanowią odpowiednik danych wejściowych. Maszyna Turinga odczytuje te dane z kolejnych komórek i przetwarza na inne symbole, czyli dane wyjściowe. Wyniki obliczeń również są zapisywane w komórkach taśmy.

Można definiować różne symbole dla maszyny Turinga. Najczęściej rozważa się jedynie symbole 0, 1 oraz tzw. znak pusty - czyli zawartość komórki, która nie zawiera żadnej danej do przetworzenia. Wbrew pozorom taki prymitywny zbiór trzech symboli jest równoważny logicznie dowolnemu innemu zbiorowi
Głowica
Aby przetwarzać dane, maszyna Turinga musi je odczytywać i zapisywać na taśmę. Do tego celu przeznaczona jest właśnie głowica zapisująco-odczytująca, która odpowiada funkcjonalnie urządzeniom wejścia/wyjścia współczesnych komputerów lub układom odczytu i zapisu pamięci.
Głowica zawsze znajduje się nad jedną z komórek taśmy. Może ona odczytywać zawartość tej komórki oraz zapisywać do niej inny symbol - na tej zasadzie odbywa się przetwarzanie danych - z jednych symboli otrzymujemy inne. Oprócz odczytywania i zapisywania symboli w komórkach głowica wykonuje ruchy w prawo i w lewo do sąsiednich komórek na taśmie. W ten sposób może się ona przemieścić do dowolnie wybranej komórki taśmy.
Przed rozpoczęciem pracy maszyny Turinga głowica jest zawsze ustawiana nad komórką taśmy zawierającą pierwszy symbol do przetworzenia. W klatce taśmy po lewo jest zapisany specjalny znak, tzw. lewy ogranicznik. Jeżeli głowica znajduje się nad lewym ogranicznikiem, to nie może go zamazać ani przesunąć się na lewo od niego. Po zakończeniu danych wejściowych taśma wypełniona jest w nieskończoność specjalnymi pustymi symbolami, tzw. blank'ami.
Układ Starowania
Przetwarzaniem informacji zarządza układ sterowania głowicą. Jego współczesnym odpowiednikiem jest procesor komputera. Układ ten odczytuje za pomocą głowicy symbole z komórek taśmy oraz przesyła do głowicy symbole do zapisu w komórkach. Dodatkowo nakazuje on głowicy przemieścić się do sąsiedniej komórki w lewo lub w prawo.
Podstawą działania maszyny Turinga są stany układu sterowania. Stan układu sterowania określa jednoznacznie jaką operację wykona, jak zareaguje maszyna Turinga, gdy odczyta z taśmy określony symbol.
Zatem operacje wykonywane przez układ sterowania zależą od dwóch czynników:
Stany będziemy określać kolejnymi nazwami: q0, q1, q2, ... ,qn, gdzie q0 jest stanem początkowym, w którym znajduje się maszyna Turinga przed rozpoczęciem przetwarzania symboli na taśmie.
Instrukcją dla maszyny Turinga jest następująca piątka symboli:

S0 i qi są tzw. częścią identyfikacyjną instrukcji. Maszyna Turinga wykonuje tyle różnych instrukcji, ile zdefiniujemy części identyfikacyjnych - w programie nie może być dwóch różnych instrukcji o identycznej części identyfikacyjnej.
Sz, qj i L/P są tzw. częścią operacyjną, która określa jakie działanie podejmuje dana instrukcja. Części operacyjne różnych instrukcji mogą być takie same - oznacza to jedynie, iż instrukcje te wykonują dokładnie to samo działanie.
Przyklad instrukcji
Jeżeli odczytanym przez głowicę symbolem z taśmy będzie symbol A, a układ sterowania znajduje się w stanie q0, to głowica zamieni ten symbol na B, stan wewnętrzny nie zmieni się (pozostanie dalej q0), a głowica przesunie się do sąsiedniej komórki po prawej stronie.
Formalna Definicja
Każdy problem, który może być intuicyjnie uznany za obliczalny, jest rozwiązywalny przez maszynę Turinga.
Sformułowanie "intuicyjnie uznany za obliczalny" uniemożliwia przeprowadzenie matematycznego dowodu tej hipotezy.
Bardziej praktyczna definicja
Każdy problem, dla którego przy nieograniczonej pamięci oraz zasobach istnieje efektywny algorytm jego rozwiązywania, da się rozwiązać na maszynie Turinga
Trzecie równoważne sformułowanie
Każdy nieinteraktywny program może być zredukowany do rozwiązującej go maszyny Turinga, a ta może być wyrażona w każdym zupełnym w sensie Turinga języku programowania.
Dlatego równoważne sformułowanie tej hipotezy mówi, że każdy istniejący algorytm można wyrazić w każdym zupełnym języku programowania.
Translacja Adresów Sieciowych (Network Adress Translation, NAT) - technika przesyłania ruchu sieciowego poprzez router, która wiąże się ze zmianą źródłowych lub docelowych adresów IP, zwykle również numerów portów TCP/UDP pakietów IP podczas ich przepływu. Zmieniane są także sumy kontrolne (zarówno w pakiecie IP, jak i w segmencie TCP/UDP), aby potwierdzić wprowadzone zmiany.
Alternatywna Definicja
NAT jest procesem modyfikującym informację o adresie IP w nagłówku pakietu IP, w momencie przesyłania ruchu przez urządzenie sieciowe. W większości konfiguracji, NAT podmienia prywatne adresy wewnątrz sieci na adresy IP publiczne, udostępniane przez dostawcę usługi dostępu do internetu. Taki zabieg pozwala komputerom w sieci domowej czy firmowej współdzielić połączenie internetowe. Dodatkowo, uzyskuje się zwiększony poziom bezpieczeństwa sieci, ponieważ dostęp do sieci wewnętrznej z zewnątrz jest mocno ograniczony.
Dwa podstawowe typy NAT:
Wyróżniamy trzy rodzaje SNAT:
W momencie, gdy wraca do nas odpowiedź na ten pakiet urządzenie NAT przypisuje pakietowi odpowiedni adres lokalnego węzła. Odwzorowania między pakietami a adresami zapamietywane są w tablicy translacji NAT.
Przyklady działania SNAT`U
Wysyłanie request`u przez (Statyczny/Dynamiczny SNAT):

Otrzymanie odpowiedzi przy (Statycznym/Dynamicznym SNAT):

Otrzymanie odpowiedzi z wlączanym PAT:

Trasowanie (Routing) - to mechanizm wyznaczania trasy i przesyłania pakietów danych w intersieci, od stacji nadawczej do stacji odbiorczej.
Intersieć - to minimum dwie sieci fizyczne połączone ze sobą za pomocą routera.
Trasowaniem zajmuje się urządzenie zwane routerem: może to być zwykły komputer jak i urządzenie specjalnie dedykowane tylko do tego zadania, tzw. router sprzętowy.
Trasowanie umożliwia danym z jednej sieci lokalnej dotrzeć do innej sieci lokalnej, która może znajdować się w dowolnym miejscu na świecie. Trasa może prowadzić przez wiele sieci pośrednich, tak więc routing jest jakby spoiwem łączącym Internet w całość. Bez routowania cały ruch danych byłby ograniczony do jednej fizycznej sieci.
UWAGA
Trasowanie realizowane jest w warstwie trzeciej (sieciowej) modelu OSI. Wyznaczane trasy pakietów danych musza być jak najbardziej optymalne – czyli możliwie najszybsze, ale umożliwiające dostarczenie wszystkich pakietów.
Pakiet to jednostka informacji, której źródłem i przeznaczeniem jest warstwa Sieciowa (warstwa 3) modelu OSI. Pakiet składa się z trzech elementów:
Nagłówek i końcówka zawierają informację sterującą przeznaczoną dla warstwy 3 w stacji odbiorczej. Można powiedzieć, że dane z wyższej warstwy są otoczone (kapsułkowane) przez nagłówek i końcówkę warstwy 3.
Datagram jest jednostką informacji, której źródłem i przeznaczeniem jest warstwa Sieciowa (warstwa 3) modelu OSI, używająca bezpołączeniowej obsługi sieci. Pakiet (połączeniowa obsługa sieci) = datagram (bezpołączeniowa)
Etapy trasowania:
Tablica Routingu
Router przechowuje tzw. tablicę routingu, dzięki której wie, jak kierować ruchem. Najważniejsze informacje zawarte w tablicy to adresy sąsiednich routerów i adresy sieci docelowych.
| Aby dotrzeć do sieci | Wyślij do urządzenia o adresie |
|---|---|
| 10.1.1.0 | 10.1.2.2 |
| 10.1.2.0 | 10.1.2.2 |
| 10.1.3.0 | Bezpośrednio połączony |
Oprócz tego w tablicy mogą się też znaleźć informacje o całościowym koszcie (metryce) wysłania daną trasą pakietu (jest to pewna liczba przypisana trasie przez protokoły routingu), nazwy czy adresy interfejsów sieciowych, przez które dany pakiet jest kierowany do sieci, flagi opisujące właściwości danej ścieżki (H - ścieżka do konkretnego komputera, a nie np. do kolejnego routera, U – ścieżka jest drożna i działa bez problemów), licznik określający czas, jaki upłynął od ostatniego uaktualnienia informacji o trasie.
Pakiet danych przechodzi pomiędzy kolejnymi sieciami. Takie kolejne przejście nazywane jest przeskokiem lub hop-em. Tablica routingu zawarta w routerze lub w komputerze sieciowym zawiera właśnie przyporządkowania adresów dotyczące jednego hopu!

Pod względem sposobu wypełniania danymi tych tablic, dzielimy routing na statyczny i dynamiczny.
Statyczny - administrator ręcznie wpisuje wszystkie adresy to tablicy routingu. Najprostszą formą budowania informacji o topologii sieci są ręcznie podane przez administratora trasy definiujące routing statyczny. Przy tworzeniu takiej trasy wymagane jest jedynie podanie adresu sieci docelowej, interfejsu, przez który pakiet ma zostać wysłany oraz adresu IP następnego routera na trasie.
Zalety
Wady
Dynamiczny - routery samodzielnie zbierają informacje i aktualizują zapisy w tablicy.
Ponieważ statyczne systemy trasowania nie mogą reagować na zmiany w sieci, to generalnie nie są one przydatne do stosowania w sieciach dużych, gdzie zmiany następują praktycznie ciągle. Dlatego większość obecnie stosowanych algorytmów trasowania to algorytmy dynamiczne, dostosowujące się do zmiennych warunków występujących w sieci, na drodze analizy aktualizujących komunikatów trasowania. W wypadku, gdy aktualizujący komunikat trasowania wskazuje, że w sieci wystąpiły zmiany, oprogramowanie trasujące ponownie oblicza trasy i wysyła do routerów nowe komunikaty aktualizujące. W ślad za tym komunikaty, przenikając przez sieć, stymulują routery do uruchomienia algorytmów trasowania i zmieniają ich tablice trasowania.
Protokoły trasowania dynamicznego są wykorzystywane przez routery do pełnienia trzech podstawowych funkcji:
Podział protokołów:
Protokoły wektora odległości:
Trasowanie może być oparte na algorytmach wektora odległości (nazywanych również algorytmami Bellmana-Forda). Nazwa pochodzi stąd, iż poszczególne routery prezentowane są jako wektory zawierające dwie informacje: dystans oraz wektor wyznaczający kierunek. Dystans opisuje całkowity koszt/metrykę danej trasy i wyrażany jest za pomocą pewnej liczby, natomiast Kierunek definiowany jest poprzez adres następnego skoku.
Etapy działania protokołu:
Router nie widzi poza swojego sąsiada i informacje o innych sieciach, nieprzyłączonych do niego bezpośrednio, uzyskuje tylko dzięki nim. Nazywa się to routingiem przez plotkowanie.

Przykładowe protokoły: RIP, EBGP.
Algorytmy trasowania na podstawie stanu łącza, ogólnie określane jako protokoły "najpierw najkrótsza ścieżka" (ang. SPF shortest path first), utrzymują złożoną bazę danych opisującą topologię sieci. W odróżnieniu od protokołów wektora odległości, protokoły stanu łącza zbierają i przechowują pełną informację na temat routerów sieci, a także o sposobie ich połączenia.
W protokołach stanu łącza każdy router przechowuje kompletną bazę danych o topologii sieci z informacjami o koszcie pojedynczych ścieżek w obrębie sieci oraz o stanie połączeń. Informacje te kompletowane są poprzez rozsyłanie tzw. pakietów LSA (Link-State Advertisement) o stanie łączy.
Przykładowe protokoły: OSPF, IS-IS, IDRP
Ostatnią formą trasowania dynamicznego jest praca hybrydowa. Choć istnieją "otwarte" zrównoważone protokoły hybrydowe, ta forma trasowania jest niemal całkowicie związana z zastrzeżonym produktem jednej firmy Cisco Systems, Inc. Protokół o nazwie EIGRP (ang. Enhanced Interior Gateway Routing Protocol) został zaprojektowany z zamiarem połączenia najlepszych cech protokołów opartych na wektorze odległości i stanie łącza, przy jednoczesnym ominięciu ich ograniczeń wydajności i innych wad.
Potrzebna informacja:
System autonomiczny – grupa sieci i routerów pod wspólną administracją (korporacje, uczelnie). Routery wewnątrz systemu autonomicznego dowolnie zarządzają trasami. Każdy system autonomiczny wybiera router lub routery przeznaczone do komunikacji z innymi systemami autonomicznymi. Odpowiadają one za przekazywanie informacji o osiągalności sieci wewnątrz „swojego” systemu do innych systemów.
Routery odpowiedzialne za komunikację z innymi systemami autonomicznymi nazywane są routerami zewnętrznymi albo brzegowymi (exterior gateways), routery działające wewnątrz systemu – wewnętrznymi (interior gateways).
Zewnętrzne:
EGP(Exterior Gateway Protocol)
Inny protokoł tego typu: (E) BGP (Exterior Border Gateway Protocol)
Wewnętrzne:
Grupę protokołów używanych przez routery wewnątrz systemu autonomicznego określa się nazwą IGP (Interior Gateway Protocols)
W jaki sposób algorytmy trasowania decydują o tym, że jedna trasa jest preferowana bardziej niż inna? Rozróżnia się obecnie następujące miary trasowania:
Długość ściężki jest najczęściej używaną miarą trasowania. Niektóre protokoły trasowania zezwalają administratorowi sieci na arbitralne przypisywanie kosztów każdemu łączu sieciowemu. W takim wypadku koszt ścieżki jest sumą kosztów związanych z każdym łączem składającym się na ścieżkę. Inne protokoły trasowania natomiast używają miary hop count, rozumianej jako liczba przejść pakietu przez urządzenia intersieciowe - np. routery - od stacji nadawczej do stacji odbiorczej.
Niezawodność, w kontekście algorytmów trasowania, odnosi się do skuteczności każdego łącza (określanego liczbą przekłamanych bitów). Niektóre łącza mogą ulegać uszkodzeniom częściej od innych. Po uszkodzeniu sieci niektóre łącza można naprawić szybciej i prościej niż inne.
Opóźnienie trasowania oznacza czas potrzebny do przesłania pakietu od stacji nadawczej do stacji odbiorczej w intersieci.
Szerokość pasma odnosi się do dostępnej pojemności ruchu w określonym łączu
Obciążenie to stopień zajętości zasobu sieciowego, np. routera. Obciążenie zależy od wielu czynników, np. stopnia wykorzystania procesora czy liczby pakietów przetwarzanych w czasie jednej sekundy.
Koszt komunikacji jest ważną miarą trasowania, przede wszystkim dlatego, że niektóre firmy nie dbają o wydajność. Nawet wtedy, gdy opóźnienia są duże, przesyłają pakiety przez własne linie zamiast korzystać z sieci publicznych, za które się płaci tylko w czasie ich używania.
Ogółny Zarys
Usługi nazewnicze wykorzystywane są do dystrybuowania informacji. One tłumaczą nazwy hostów na adresy IP. Internetowym standardem jest DNS, ale w pewnych sytuacjach wykorzystywane są NIS i WINS.
DNS(ang. Domain Name System, system nazw domenowych) to system serwerów oraz protokół komunikacyjny zapewniający zamianę adresów znanych użytkownikom Internetu na adresy zrozumiałe dla urządzeń tworzących sieć komputerową. Dzięki wykorzystaniu DNS nazwa mnemoniczna, np. pl.wikipedia.org, może zostać zamieniona na odpowiadający jej adres IP, czyli 145.97.39.135.
Adresy DNS składają się z domen internetowych rozdzielonych kropkami. Dla przykładu w adresie Wikipedii org oznacza domenę funkcjonalną organizacji, wikipedia domenę należącądo fundacji Wikimedia, a pl polską domenę w sieci tej instytucji. W ten sposób możliwe jest budowanie hierarchii nazw, które porządkują Internet.
Strona Techniczna
Podstawą technicznego systemu DNS jest ogólnoświatowa sieć serwerów przechowujących informacje na temat adresów domen. Każdy wpis zawiera nazwę oraz odpowiadającą jej wartość, najczęściej adres IP. System DNS jest podstawą dla rozwiązywania nazw hostów w Internecie.
DNS to również protokół komunikacyjny opisujący sposób łączenia się klientów z serwerami DNS. Częścią specyfikacji protokołu jest również zestaw zaleceń, jak aktualizować wpisy w bazach domen internetowych. Na świecie jest wiele serwerów DNS, które odpowiadają za obsługę poszczególnych domen internetowych. Domeny mają strukturę drzewiastą, na szczycie znajduje się 13 głównych serwerów (root servers) obsługujących domeny najwyższego poziomu (TLD – top level domains).
Serwery najwyższego poziomu z reguły posiadają tylko odwołania do odpowiednich serwerów DNS odpowiedzialnych za domeny niższego rzędu, np. serwery główne (obsługujące między innymi TLD.com) wiedzą, które serwery DNS odpowiedzialne są za domenę example.com. Serwery DNS zwracają nazwę serwerów odpowiedzialnych za domeny niższego rzędu. Możliwa jest sytuacja, że serwer główny odpowiada, że dane o domenie example.com posiada serwer dns.example.com. W celu uniknięcia zapętlenia w takiej sytuacji serwer główny do odpowiedzi dołącza specjalny rekord (tak zwany glue record) zawierający także adres IP serwera niższego rzędu (w tym przypadku dns.example.com).
Wewnątrz każdej domeny można tworzyć tzw. subdomeny - stąd mówimy, że system domen jest 'hierarchiczny'. Przykładowo wewnątrz domeny .pl utworzono wiele domen:
Nazwy domen i poszczególnych komputerów składają się z pewnej liczby nazw, oddzielonych kropkami. Ostatnia z tych nazw jest domeną najwyższego poziomu. Każda z tych nazw może zawierać litery, cyfry lub znak '-'. Od niedawna w nazwach niektórych domen można używać znaków narodowych (IDN) takich jak 'ą' czy 'ż', ale większośćwspółczesnych programów nie przewiduje możliwości wykorzystania takich funkcji. Wewnątrz każdej z poddomen można tworzyć dalsze poddomeny, np. w domenie 'wikipedia.org' można utworzyć domenępl.wikipedia.org.
DNS, jako system organizacyjny, składa się z dwóch instytucji - IANA i ICANN. Nadzorująone ogólne zasady przyznawania nazw domen i adresów IP. Jednak te dwie instytucje nie sąw stanie zajmować się całym światem i dlatego cedują swoje uprawnienia na szereg lokalnych instytucji i firm.
Najważniejsze cechy DNS:
Rodzaje zapytań DNS
Zmusza serwer do znalezienia wymaganej informacji lub zwrócenia wiadomości o błędzie. Ogólną zasadą jest, że zapytania od resolwera (program, który potrafi wysyłać zapytania do serwerów DNS) do serwera są typu rekurencyjnego, czyli resolwer oczekuje podania przez serwer adresu IP poszukiwanego hosta. Wykonywanie zapytań rekurencyjnych pozwala wszystkim uczestniczącym serwerom zapamiętać odwzorowanie (ang. DNS caching), co podnosi efektywność systemu.
Wymaga od serwera jedynie podania najlepszej dostępnej mu w danej chwili odpowiedzi, przy czym nie musi on łączyć się jeszcze z innymi serwerami. Zapytania wysyłane pomiędzy serwerami są iteracyjne, przykładowo wiarygodny serwer domeny org nie musi znać adresu IP komputera www.pl.wikipedia.org, podaje więc najlepszą znaną mu w tej chwili odpowiedź, czyli adresy serwerów autorytatywnych dla domeny wikipedia.org
Odpowiedzi na zapytania
Dotyczące domeny w strefie, nad którą dany serwer ma zarząd, pochodzą one bezpośrednio z bazy danych serwera; jest to pozytywna odpowiedź zwracana do klienta, która w komunikacie DNS zawiera ustawiony bit uwierzytelniania (AA – Authoritative Answer) wskazujący, że odpowiedź została uzyskana z serwera dokonującego bezpośredniego uwierzytelnienia poszukiwanej nazwy
Dane które zwraca serwer pochodzą spoza zarządzanej przez niego strefy; odpowiedzi nieautorytatywne są buforowane poprzez serwer przez czas TTL wyrażony w sekundach, wyspecyfikowany w odpowiedzi, a następnie po upływie czasu są usuwane
Komunikaty DNS
Zapytania i odpowiedzi DNS są najczęściej transportowane w pakietach UDP. Każdy komunikat musi się zawrzeć w jednym pakiecie UDP (standardowo 512 oktetów, ale wielkość tę można zmieniać pamiętając również o ustawieniu takiej samej wielkości w MTU – Maximum Transmission Unit). W innym przypadku przesyłany jest protokołem TCP i poprzedzony dwubajtową wartością określającą długość zapytania i długość odpowiedzi (bez wliczania tych dwóch bajtów).
NAGLÓWEK - (Header)
ZAPYTANIE - (Question) do serwera nazw
ODPOWIEDŻ - (Answer) zawiera rekordy będące odpowiedzią
ZWIERZCHNOŚĆ - (Authority) wskazuje serwery zwierzchnie dla domeny
DODATKOWE - (Additional) sekcja informacji dodatkowych
| Ex. 1 | Ex. 2 | Ex. 3 |
|---|---|---|
| Ts | Ts | Ts |
Wirtualna sieć lokalna, VLAN (ang. virtual local area network) - sieć komputerowa wydzielona logicznie w ramach innej, większej sieci fizycznej.
Wirtualne sieci lokalne (Virtual Local Area Networks, VLANs) umożliwiają podział większej fizycznej sieci komputerowej na logiczne, odizolowane segmenty. Kształtowanie przepływu ruchu między sieciami VLAN odbywa się w warstwie 3. modelu OSI.
Virtual LAN dzieli fizyczne łącza na logiczne segmenty, ale sposób zaprojektowania wirtualnej sieci lokalnej zależy od administratora, a raczej przyjętych w organizacji założeń w zakresie kształtowania przepływu ruchu oraz wymaganego poziomu bezpieczeństwa. W ten sposób na jednym fizycznym przełączniku można utworzyć dwie (lub więcej) odizolowane od siebie sieci lokalne.
Tylko urządzenia przynależące do tej samej sieci VLAN mogą komunikować się ze sobą, każda sieć VLAN tworzy bowiem niezależną domenę rozgłoszeniową. Przełączniki przekazują ruch transmisji pojedynczej (unicast), grupowej (multicast) i rozgłoszeniowej (broadcast) tylko w ramach jednego segmentu sieci LAN. Poza izolacją segmentów sieci podejście to pozwala też ograniczyć zalewanie portów przełącznika rozgłoszeniami z protokołów ARP i DHCP, które nigdy nie przekraczają granic sieci VLAN.
Mechanizm routingu między VLAN, choć wymaga zastosowania dodatkowych urządzeń, pozwala kształtować przepływy ruchu między poszczególnymi segmentami sieci komputerowej. Mowa tutaj o kontroli dostępu, filtrowaniu ruchu na zaporze sieciowej czy zapewnianiu jakości usług (QoS).
Praktyczne zastosowanie
Sieć VLAN może służyć do segmentacji według struktury organizacyjnej. W instytucjach publicznych komputery pracowników działów finansowych i HR nie powinny komunikować się ze względów bezpieczeństwa z urządzeniami pozostałego personelu biurowego. Z kolei w firmie produkcyjnej technologia VLAN może odizolować ruch sieci komputerowej udostępnianej pracownikom biurowym od sieci komputerowej wykorzystywanej w wydziałach produkcyjnych na potrzeby zbierania danych i sterowania maszynami.
Inne praktyczne zastosowanie sieci VLAN to segmentacja ruchu sieciowego ze względu na jego typ. Podejście to sprawdzi się w każdej instytucji, nawet gdy nie ma jawnej potrzeby izolowania ruchu według struktury organizacyjnej. Oddzielne VLAN stosuje się dla serwerów, punktów końcowych (stacje robocze, laptopy), drukarek, urządzeń mobilnych (strategia BYOD), telefonów VoIP, sieci Wi-Fi dla gości, sieci zarządzania (management) czy strefy DMZ.
Protokół IEEE 802.1Q
VLAN to wydzielona logicznie sieć komputerowa warstwy 2. (łącza danych) modelu OSI. Grupuje logicznie porty jednego lub wielu przełączników sieciowych niezależnie od ich położenia. Podstawowym, powszechnie stosowanym protokołem oznaczania ramek i trunkingu jest IEEE 802.1Q. Protokół ten, nazywany także Dot1q, stał się branżowym standardem definiującym sposób obsługi VLAN w sieciach Ethernet.
Działanie sieci VLAN bazuje na dodawaniu 4-bajtowych znaczników (tagów) wewnątrz nagłówka ramek Ethernet, które pozwalają urządzeniom sieciowym sterować przepływem ruchu. Znacznik ten, o nazwie 802.1Q Header, umieszczany jest między polem adresu źródłowego (Source MAC) a polem wskazującym na typ ramki/długość (EtherType/Size). Pierwsze dwa bajty tego znacznika (Tag Protocol ID, TPID) mają stałą wartość 0x8100 i umożliwiają przełącznikowi odróżnienie znakowanej ramki 802.1Q od ramki nieznakowanej, która w tym miejscu miałaby pole EtherType/Size. Pozostałe dwa bajty (Tag Control Information, TCI) zawierają informacje służące do oznaczenia priorytetu ramki (definiowany w standardzie 802.1p), standardu sieci LAN (Ethernet lub Token Ring) oraz numeru wirtualnej sieci (VLAN ID), do której przynależy dana ramka. Wspomniane pole VLAN ID, stanowiące identyfikator sieci wirtualnej, ma długość 12 bitów i pozwala skutecznie przypisać ramkę do właściwego segmentu VLAN. W rezultacie na przełączniku można zdefiniować maksymalnie do 4096 sieci VLAN, z czego dwie są zarezerwowane do innych celów, a VLAN 1 pełni funkcję sieci natywnej.
W tym miejscu warto też wspomnieć o innym protokole znakowania i trunkingu. InterSwitch Link (ISL) to własnościowy protokół Cisco używany w przełącznikach tej firmy. Oryginalna ramka Ethernet pozostaje niezmieniona, jest bowiem kapsułkowana w ramce ISL, której nagłówek zawiera znacznik VLAN ID. Protokół ISL został uznany za przestarzały, nie powinien być dalej używany. Co więcej, nie jest wspierany przez najnowsze przełączniki Cisco.
Punkty końcowe mogą komunikować się ze sobą w ramach jednej sieci VLAN. Przekazywanie ruchu sieciowego między sieciami VLAN wymaga zastosowania routera lub przełącznika działającego w warstwie 3. (sieci) modelu OSI.
| Ex. 1 | Ex. 2 | Ex. 3 |
|---|---|---|
| Ts | Ts | Ts |
Są 2 rodzaje optymalizacji:
Pierwsza z podanych klasyfikacji wyróżnia optymalizację statyczną i optymalizację dynamiczną. Optymalizacja statyczna polega na znalezieniu „najlepszego” planu wykonania zapytania, przed rozpoczęciem wykonywania zapytania. W trakcie realizacji zapytania plan wykonania zapytania nie ulega już zmianie – stąd nazwa optymalizacja statyczna. Optymalizacja dynamiczna polega na znalezieniu „najlepszego” planu wykonania zapytania, przed rozpoczęciem wykonywania zapytania, ale później, w trakcie wykonywania zapytania jego plan wykonania może ulęgać zmianie. Aktualnie, komercyjne systemy baz danych zapewniają jedynie optymalizację statyczna, choć efektywność takiej optymalizacji jest najczęściej niższa aniżeli efektywność optymalizacji dynamicznej. Optymalizacja dynamiczna jest jednak znacznie bardziej kosztowna. Druga z podanych klasyfikacji wyróżnia optymalizację pojedynczego zapytania oraz jednoczesną optymalizację wielu zapytań. W przypadku optymalizacji pojedynczego zapytania, optymalizacji podlega tylko jedno zapytanie. W przypadku jednoczesnej optymalizacji wielu zapytań, częściowe wyniki wykonania jednego zapytania mogą być wykorzystane przez wiele innych zapytań, co prowadzi do minimalizacji czasu wykonania zbioru zapytań. W chwili obecnej systemy komercyjnych baz danych zapewniają jedynie optymalizację pojedynczego zapytania.
Ogółny proces optymalizacji zapytań:
W wyniku zastowania transformacji algebraicznych uzyskujemy zbiór najlepszych planów wykonania pojedynczych bloków zapytania. Pozostaje jeszcze problem połączenia bloków, w szczególności, problem zdefiniowania porządku wykonywania operacji połączenia. Wybór kolejności wykonywania operacji połączenia, tzn. wybór uszeregowania operacji połączenia, kończy proces optymalizacji zapytania.
Dekompozycja
Pierwszą fazą przetwarzania zapytania jest dekompozycja zapytania. Celem procesu dekompozycji zapytania jest transformacja zapytania wyrażonego w języku wysokiego poziomu na wyrażenie algebry relacji i weryfikacja syntaktycznej i semantycznej poprawności zapytania. Proces dekompozycji składa się z następujących etapów:
Analiza zapytania
Celem etapu analizy jest analiza syntaktyczna poprawności zapytania. W skład tej analizy wchodzi weryfikacja poprawności atrybutów i relacji (czy w bazie danych występują wyspecyfikowane w zapytaniu relacje i atrybuty, czy zapytanie poprawnie specyfikuje typy danych).
Następnie, zapytanie wyrażone w języku SQL jest transformowane do postaci reprezentacji wewnętrznej (wyrażenia algebry relacji, które można zapisać w postaci drzewa, jak na przykładzie poniżej), bardziej adekwatnej do procesu dalszego przetwarzania zapytania.
Select *
From Employee E, Department D
Where E. deptId = D. DeptId
And E.position = 'manager' and D.location = ‘London';

Normalizacja
Kolejnym etapem fazy dekompozycji jest normalizacja zapytania. Celem etapu normalizacji zapytania jest przekształcenie wewnętrznej reprezentacji zapytania do znormalizowanej postaci koniunkcyjnej lub dysjunkcyjnej. W fazie tej sekwencja predykatów selekcji jest przekształcana do normalnej postaci koniunkcyjnej lub normalnej postaci dysjunkcyjnej. Postać dysjunkcyjna jest, najczęściej, mniej efektywna, gdyż wymaga niezależnego wartościowania poszczególnych składowych wyrażenia. Przykłady postaci koniunkcyjnej i dysjunkcyjnej wyrażenia zapytania:

Analiza semantyczna zapytania(1)
Kolejnym, ważnym, etapem dekompozycji zapytania jest etap analizy semantycznej
zapytania. Celem analizy semantycznej zapytania jest odrzucenie niepoprawnie
sformułowanych lub sprzecznych zapytań. Zapytanie jest niepoprawnie sformułowane,
jeżeli jego elementy składowe nie prowadzą do generacji wyniku. Zapytanie jest
sprzeczne, jeżeli jego predykaty nie mogą być spełnione przez żadną krotkę w bazie
danych. Przykładem klauzuli, która jest sprzeczna jest wyrażenie:
position = ‘manager’
and position = ‘assistant’.
Zakładając, że baza danych jest w 1NF, nie istnieje w bazie danych żadna krotka, któraby
jednocześnie spełniała oba predykaty. Wartość sprzecznej klauzuli interpretujemy jako
wartość FALSE. W związku z tym, wyrażenie zawierające sprzeczna klauzulę można
uprościć.
Przykładowo, wyrażenie
(position = ‘manager’ and position = ‘assistant’) or salary > 1000;
ze względu na sprzeczność klauzuli : „position = ‘manager’ and position = ‘assistant’”
można uprościć do postaci „salary > 1000”
Analiza semantyczna zapytania(2)
Niestety, algorytmy oceny poprawności semantycznej zapytań istnieją tylko dla pewnej klasy zapytań, nie zawierających dysjunkcji i negacji. W jaki sposób rozwiązywany jest problem zapytań niepoprawnie sformułowanych oraz zapytań sprzecznych? Rozwiązanie problemu zapytań niepoprawnie sformułowanych opiera się na konstrukcji tak zwanego grafu połączenia relacji. W grafie tym, wierzchołki odpowiadają relacjom, natomiast luki odpowiadają operacjom połączenia wyspecyfikowanych w zapytaniu. Dodatkowo, graf połączenia relacji zawiera wierzchołek reprezentujący wynik zapytania. Jeżeli graf połączenia relacji nie jest spójny, to zapytanie jest niepoprawnie sformułowane.
Rozwiązanie problemu zapytań niepoprawnie sformułowanych opiera się na konstrukcji tak zwanego grafu połączeń atrybutów.
Przykłady tworzenia tych grafów (str: 10-12)
Kolejnym etapem fazy dekompozycji jest upraszczanie zapytań. Celem tego etapu jest identyfikacja wyrażeń redundantnych, eliminacja wspólnych podwyrażeń, i transformacja zapytania do równoważnej postaci, ułatwiającej dalsze przekształcanie zapytania. Transformacja zapytania do postaci równoważnej polega na zastosowaniu znanych reguł algebry relacji.
Kolejnym etapem fazy dekompozycji jest etap restrukturyzacji, czy tez transformacji zapytania. Zanim jednak przejdziemy do przedstawienia podstawowych reguł transformacji, wróćmy na chwilę do problemu konstrukcji podstawowych bloków zapytania. Tradycyjne podejście do konstrukcji bloków zapytania opera się na zastosowaniu transformacji algebraicznych, jednakże, zbiór stosowanych transformacji różni się zasadniczo dla różnych systemów komercyjnych.
Co więcej, nie wszystkie transformacje gwarantują minimalizację czasu wykonania danego bloku. W ostatnim czasie, coraz częściej, konstrukcja bloków opiera się na optymalizacji kosztowej, w której, dla każdego bloku, konstruujemy możliwe plany wykonania danego bloku i szacujemy koszt i rozmiar wykonania każdego planu. Ostatecznie wybierany jest plan wykonania o najniższym szacowanym koszcie. Do zakończenia procesu optymalizacji pozostaje jeszcze znalezienie najlepszego drzewa operacji połączenia, łączącego wyniki wykonania bloków zapytania. Tradycyjne podejście do problemu znajdowania najlepszego drzewa operacji połączenia (nazywane często podejściem w stylu systemu R) polega na zastosowaniu algorytmu programowania dynamicznego.
Każdy plan wykonania zapytania jest częściowo uporządkowanym zbiorem operacji. W skład tego zbioru operacji wchodzą: operacja skanowania, selekcji, projekcji, połączenia, produktu kartezjańskiego, operacje grupowania i agregacji. Problem znalezienia najlepszego planu wykonania zapytania obejmuje, z jednej strony, określenie kolejności wykonania operacji wchodzących w skład zapytania, z drugiej, określenia metody wykonania poszczególnych operacji. Przykładowo, mamy dwie metody dostępu do relacji: bezpośrednie skanowanie (odczyt) relacji lub dostęp do relacji poprzez skanowanie indeksu założonego na relacji. Podstawowa reguła optymalizacji mówi, że wszystkie operacje unarne (projekcja i selekcja) należy przesunąć w dół drzewa zapytania, tzn. wykonywać w pierwszej kolejności. Operacje te charakteryzują się silną własnością redukcji (filtrowania) przetwarzanych danych. Redukując rozmiar przetwarzanych danych, operacje unarne prowadzą do poprawy efektywności wykonywania operacji binarnych. Dlatego, operacje binarne (połączenie, produkt kartezjański) należy przesunąć w kierunku korzenia drzewa zapytania. Dla operacji binarnych, np. połączenia, poza określeniem kolejności ich wykonywania, należy wybrać również metodę ich wykonania (dla połączenia - nested loop, sort-merge, hash-join). Najczęściej, na końcu planu wykonania zapytania znajdują się operacje grupowania i agregacji.
Reguły transformacji oparte na algebrze relacji (Strony: 17-20)
Ważne
Zapytania zawierające skorelowane podzapytania zagnieżdżone są kosztowne w realizacji, gdyż wymagają sprawdzenia, dla każdej krotki zapytania zewnętrznego, czy spełniony jest dla tej krotki warunek podzapytania skorelowanego. Klasyczna metoda transformacji takich zapytań polega na przepisaniu zapytania w taki sposób, aby usunąć zagnieżdżenie (ang. unnesting). Usunięcie zagnieżdżenia polega na zastąpieniu zagnieżdżenia operacją połączenia.
Przykłady transformacji zagnieżdzionych zapytań (Strony: 21-26)
Zagadnienie optymalizacji jest zagadnieniem trudnym i istnieje bardzo wiele, specyficznych, reguł transformacji dla różnych typów zapytań. Co więcej, nie zawsze jest możliwe przetransformowanie zapytań w taki sposób, aby nie zawierało podzapytań (szczególnie dla podzapytań skorelowanych). W szczególnych przypadkach, gdy czas realizacji zapytania jest nieakceptowalny, można zastosować technikę redukcji rozmiarów relacji uczestniczących w zapytaniu opartą o sekwencję operacji półpołączenia. Technika ta jest wykorzystywana do optymalizacji zapytań rozproszonych w systemach rozproszonych baz danych.
Uwierzytelnianie (ang. authentication) - roces polegający na potwierdzeniu zadeklarowanej tożsamości podmiotu biorącego udział w procesie komunikacji. Celem uwierzytelniania jest uzyskanie określonego poziomu pewności, że dany podmiot jest w rzeczywistości tym, za który się podaje.
W systemach informatycznych stosuje się następujące rodzaje uwierzytelniania:



Klasyczne uwierzytelnianie użytkownika
W przypadku wielu współczesnych środowisk informatycznych, systemów operacyjnych lub systemów zarządzania bazami danych, funkcjonuje klasyczny mechanizm uwierzytelniania poprzez hasło. Proces uwierzytelniania rozpoczyna klient żądając zarejestrowania w systemie (login). Serwer pyta o identyfikator (nazwę) użytkownika, a następnie o hasło i decyduje o dopuszczeniu do sieci. W większości przypadków nazwa użytkownika i hasło są przesyłane tekstem jawnym, co stanowić może kolejny problem zapewnienia poufności, jaką właśnie mamy osiągnąć stosując opisywany mechanizm. Stąd też takie klasyczne podejście nadaje się do wykorzystania jedynie w ograniczonej liczbie przypadków, kiedy np. mamy uzasadnioną skądinąd pewność wykluczenia możliwości podsłuchu danych uwierzytelniających.
Hasła nie są najefektywniejszą, ani najbezpieczniejszą formą weryfikacji tożsamości użytkownika, z następujących powodów:
Zdalne potwierdzanie tożsamości
W środowisku sieci TCP/IP wypracowano mechanizm prostego potwierdzania tożsamości użytkownika, który żąda zdalnego uwierzytelniania. W tym celu powstał standard RFC 1413 opisujący usługę o nazwie identd. Niezależnie od jej aktualnej przydatności i powszechności warto zdawać sobie sprawę z istoty jej działania, którą łatwo opisać w następujący sposób:

Należy też zdawać sobie sprawę z potencjalnych zagrożeń jakie niesie udostępnianie przez usługę ident informacji o przynależności procesów dokonujących komunikacji sieciowej (nie tylko klientów). W standardzie RFC 1413 oraz w praktycznych implementacjach nie realizuje się bowiem uwierzytelniania podmiotu żądającego informacji z tej usługi, może ona być zatem również nadużyta przez potencjalnego włamywacza.
Procedury uwierzytelniania jednokrotnego są częściowym rozwiązaniem problemu ochrony danych uwierzytelniających przed złamaniem w systemie wielozasobowym, np. sieci komputerowej z wieloma serwerami.
Ideą procedury uwierzytelniania jednokrotnego jest minimalizacja ilości wystąpień danych uwierzytelniających w systemie - hasło powinno być podawana jak najrzadziej. Zgodnie z tą zasadą, jeśli jeden z komponentów systemu (np. system operacyjny) dokonał pomyślnie uwierzytelniania użytkownika, pozostałe komponenty (np. inne systemy lub zarządcy zasobów) ufać będą tej operacji i nie będą samodzielnie wymagać podawania ponownie danych uwierzytelniających. Przy tym jest możliwe teoretycznie, że wszystkie komponenty samodzielnie korzystają z odmiennych mechanizmów uwierzytelniana. Wówczas, dodatkowo po pierwszorazowym uwierzytelnieniu użytkownika, system może oddelegować specjalny moduł do przechowywania odrębnych danych uwierzytelniających użytkownika i poświadczania w przyszłości jego tożsamości wobec innych komponentów systemu.
chemat SSO przedstawia poniższy rysunek. W przedstawionej na rysunku sytuacji tylko jeden serwer dokonuje uwierzytelniania klienta, reszta ufa uwierzytelnianiu dokonanemu przez ten serwer.

Istota wykorzystania haseł jednorazowych wynika zamiaru ochrony ich przed przechwyceniem i nieautoryzowanym wykorzystanie, w przyszłości. Jednak nie polega na zapewnieniu ich poufności w transmisji lecz na uczynieniu ich de facto bezwartościowymi po przechwyceniu. Opiera się na, jak sama nazwa wskazuje, tylko użyciu danej postaci hasła tylko raz. Hasła jednorazowe mają przy każdym kolejnym uwierzytelnieniu inną postać. Raz przechwycone hasło jednorazowe nie jest przydatne, bowiem przy kolejnym uwierzytelnieniu będzie obowiązywać już inne. Komunikacja między podmiotami procesu uwierzytelniania może być zatem jawna. Stosujące takie hasła procedury uwierzytelniania muszą jedynie oferować brak możliwości odgadnięcia na podstawie jednego z haseł, hasła następnego.
Hasła jednorazowe generowane są przy pomocy listy haseł, synchronizacji czasu lub metody zawołanie-odzew. Dostępne są najczęściej w następujących postaciach: listy papierowe, listy-zdrapki, tokeny programowe i tokeny sprzętowe.
Lista haseł
Listy haseł to najprostsza i najtańsza metoda identyfikacji metodą haseł jednorazowych. Użytkownik otrzymuje listę zawierająca ponumerowane hasła. Ta sama lista zostaje zapisana w bazie systemu identyfikującego. W trakcie logowania użytkownik podaje swój identyfikator, a system prosi o podanie hasła z odpowiednim numerem. Klient za każdym razem posługuje się kolejnym niewykorzystanym hasłem z listy.

Metoda synchronizacji czaswoej
W metodzie z synchronizacją czasu (time synchronization) klient generuje unikalny kod w funkcji pewnego parametru X użytkownika (identyfikatora, kodu pin, hasła, numeru seryjnego karty identyfikacyjnej) oraz bieżącego czasu. Serwer następnie weryfikuje otrzymany od klienta kod korzystając z identycznej funkcji (z odpowiednią tolerancją czasu).

Metoda "Zawołanie-Odzew"
Natomiast w metodzie zawołanie-odzew (challenge-response) serwer pyta o nazwę użytkownika, a następnie przesyła unikalny ciąg („zawołanie"). Klient koduje otrzymany ciąg (np. swoim hasłem lub innym tajnym parametrem pełniącym rolę klucza) i odsyła jako „odzew". Serwer posługując się identycznym kluczem weryfikuje poprawność odzewu.

Metoda Tokenów
Tokeny programowe to specjalne programy generujące hasła. W zależności od implementacji program na podstawie kwantu czasu lub zawołania serwera generuje hasło jednorazowe, które weryfikuje serwer.
Token sprzętowy jest małym przenośnym urządzeniem spełniającym wszystkie funkcje tokenu programowego.
Pewną ciekawostką zyskującą na popularności jest wykorzystanie telefonu komórkowego w uwierzytelnianiu za pomocą haseł jednorazowych. Cały proces polega przesłaniu hasła jednorazowego z serwera na telefon w postaci wiadomości SMS. W tym przypadku rola telefonu jako swoistego tokena sprowadza się tylko do medium odbierającego i wyświetlającego dane.
Inne mechanizmy uwierzytelniania
Do uwierzytelniania użytkowników można wykorzystać również przedmioty, których posiadaniem musi się wykazać uwierzytelniany. Mogą to być np. karty magnetyczne, karty elektroniczne czy tokeny USB. Ponadto, w przypadku ludzi, można posłużyć się również cechami osobowymi wynikającymi z odmienności parametrów niektórych naturalnych składników organizmu (uwierzytelnianie biometryczne), takich jak m.in.:
Autoryzacja i kontrola dostępu zaczyna się tam, gdzie kończy się uwierzytelnianie. Kiedy podmiot zabezpieczeń SP (Security Principal) podejmuje próbę uzyskania dostępu do chronionego obiektu lub usługi, proces autoryzacji przejmuje jego tożsamość i używa jej do określenia jego uprawnień.
Zadania autoryzacji i kontroli dostępu legalnych użytkowników należą do podstawowych funkcji systemów operacyjnych czy systemów zarządzania bazą danych oraz środowisk przetwarzania rozproszonego. W większości przypadków te funkcje są realizowane podobnie.
Jeżeli SP próbuje uzyskać dostęp (np. do pliku na serwerze WWW), usługa autoryzacji kwerenduje bazę danych, aby określić, jakie uprawnienia związane z tym plikiem ma SP. System kontroli dostępu jest programem lub procesem egzekwującym uprawnienia i przywileje. Generalnie, część autoryzacyjna systemu określa, że SP może tylko czytać dany plik, a system kontroli dostępu w rzeczywistości zapewnia, że nie może tego pliku zmodyfikować.
Modele kontroli dostępu opisują ogólne metody używane w poszczególnych domenach bezpieczeństwa do kontroli dostępu na styku SP i żądanej usługi czy obiektu.
Główna różnica między modelem dostępu RBAC a DAC polega na tym, że grupy DAC mają na ogół określać ogólną przynależność (np. zespół działu kadr), podczas gdy wyznacznikiem RBAC są działania (np. wykonywane przez pracownika działu kadr, działu płac itp.).
Wiele modeli RBAC (w tym sporo zaimplementowanych jako warstwa nad systemami DAC) dopuszcza tylko szczególne uprawnienia w trakcie wykonywania przez SP koniecznych działań. I tak np. w tym modelu pracownik zajmujący się wypłatami ma dostęp do bazy danych płac tylko wtedy, gdy korzysta z aplikacji płacowej.
W domenie bezpieczeństwa opartej na DAC pracownik działu płac będzie miał prawdopodobnie uprawnienia do zapisów oraz odczytu całej bazy danych, i te uprawnienia będą stałe oraz niezależne od aplikacji.
Systemy RBAC są dużo bardziej bezpieczne. Preferuje je większość ekspertów ds. bezpieczeństwa, ale również wymagają znacząco większego wysiłku po stronie administrowania, podejmowania decyzji o uprawnieniach, określania delegacji ról. W codziennym użytkowaniu RBAC wymaga większej automatyzacji i stosowania globalnych praktyk zarządzania.
W praktyce rzadko można spotkać domenę bezpieczeństwa, gdzie zastosowano tylko jeden model kontroli dostępu. System operacyjny Windows jest zbudowany wokół DAC, ale już w systemie Vista Microsoft dodał MAC (stosując obowiązkową kontrolę integralności), a RBAC jest dostępny na poziomie sieciowym w Active Directory. Wiele domen opartych na DAC i RBAC umożliwia także klasyfikowanie (etykietowanie) danych, podobnie jak systemy oparte na MAC, co pomaga ustalić właściwe uprawnienia i inne zabezpieczenia, które mają być stosowane na kolejnym poziomie ochrony ważnych danych.
Aby zapewnić odpowiedni poziom bezpieczeństwa, niezbędne jest rejestrowanie pomyślnych lub podejmowanych prób dostępu, a także działań po uzyskaniu dostępu. Rozliczanie jest zazwyczaj uważane za bardziej ogólną metodę rejestrowania niż audyt. System rozliczeniowy może rejestrować tylko pojedyncze pomyślne logowania (na sesję), liczbę przesłanych danych lub całkowity czas aktywności sesji. Z audytem wiąże się dużo bardziej szczegółowy poziom kontroli, pozwalający śledzić każdą wykonywaną przez SP akcję (lub próbę wykonania) - przeglądane lub modyfikowane pliki i foldery - oraz rejestrować czas wydarzenia.
Audyt i system rozliczania dodatkowo komplikują systemy współdzielone, tożsamości i hasła. Silny system AAA wymaga unikatowych tożsamości, aby każda indywidualna akcja mogła zostać zarejestrowana oddzielnie. Poziom rozliczalności i audytu może być ustawiony przez administratora, aczkolwiek zależy częściowo od systemu AAA i używanych protokołów. Dobry system rozliczania i audytu śledzi każdą akcję wykonywaną przez każdego SP - od tworzenia obiektu aż do jego usunięcia (włączając w to zdarzenia logowania i zmiany w dzienniku zdarzeń audytu). Więcej o tym tutaj (Strony 2-5)
Alfabet
Alfabetem nazywamy dowolny niepusty zbiór skooczony. Elementy alfabetu nazywami symbolami.
Słowa
Słowem
I Wyrażenia regularne
Def
Niech będzie dany zbiór Π = { ∅, λ ,+,· ,* ,( ,) } oraz alfabet Σ, przy czym Σ ∩ Π = ∅.
Wyrażeniem regularnym nad alfabetem Σ nazywamy każde słowo A ∊ (Σ, ∏)* spełniające jeden z poniższych warunków:
Rodzinę wyrażeo regularnych nad alfabetem Σ oznaczamy przez WR(Σ)
(lub WR jeśli nie będzie wątpliwości
dotyczących alfabetu)
II Języki regularne
Def
Niech będzie dany alfabet Σ oraz rodzina wyrażeń regularnych WR zdefiniowanych nad tym alfabetem. Każdemu wyrażeniu regularnemu A∊WR przyporządkowujemy język L(A) za pomocą definicji rekurencyjnej ze względu na budowę wyrażenia regularnego A:
Mówimy, że język L(A) jest językiem generowanym przez wyrażenie regularne A, natomiast o słowach należących do języka L(A) mówimy, że są generowane przez wyrażenie regularne A.
Def.
Językiem regularnym nazywamy każdy język formalny L nad danym alfabetem, dla którego istnieje wyrażenie regularne A takie, że: L=L(A) . Klasę języków regularnych oznaczamy przez JR.
Każdy język regularny może byd generowany przez wiele wyrażeo regularnych. Def. Mówimy, że wyrażenia regularne A i B są równoważne, gdy generują ten sam język, tzn
AUTOMAT SKOŃCZONY Rabina-Scotta
Automatem skończonym (typu Nas-labmda) nazywamy uporządkowaną piątkę
Język L złożony ze wszystkich słów akceptowanych przez automat skooczony M nazywamy generowanym przez automat M i oznaczamy przez L(M)
Gdzie:
Zbiór wszystkich języków generowanych przez automaty skończone oznaczamy symbolem ZJNAS-λ.
Przykład automatu skończonego:

Automatem skończonym type DAS nazywamy uporządkowaną piątke:
Język Lzłożony ze wszystkich słów akceptowanych przez automat M typu DAS nazywamy generowanym przez automat Mi oznaczamy przez L(M)
Zbiór wszystkich języków generowanych przez automaty typu DAS oznaczamy symbolem ZJDAS.
TW. 3
Jeżeli
jest automatem typu DAS, to generuje on język L wtedy i tylko wtedy, gdy automat
generuje język L`.
Przykład automatu typu DAS:

Ważne Tw. Zbiory języków generowanych przez automaty typu DAS i NAS-λ są sobie równe:
Def Gramatyką bezkontekstową nazywamy uporządkowaną czwórkę:
Def Językiem generowanym przez gramatykę G, nazywamy zbiór
Słowo A należy do języka L opisanego przez daną gramatykę G, jeśli istnieje ciąg produkcji prowadzący od symbolu zmiennej początkowej S do danego słowa. Mówimy wówczas, że słowo A jest wyprowadzone w gramatyce G.
Def
Językiem Bezkontekstowym nazywamy język, dla którego istnieje gramatyka bezkontekstowa generująca ten język.Zbiór języków generowanych przez gramatyki bezkontekstowe oznaczamy przez ZJB.
Def
Automatem ze Stosem(AZS) nazywamy uporządkowaną siódemkę:
Opisem chwilowym automatu M nazywamy każdą trójkę (S,A,B), gdzie:
Przykładowy auyomat ze Stosem:

Tw. 17
Zbiór języków akceptowanych przez automaty ze stosem jest równy zbiorowi języków bezkontekstowych.
Maszyny Turinga
Def. Maszyną Turinga (MT) nazywamy uporządkowany układ:
Def
Język L złożony ze wszystkich słów akceptowanych przez maszyne Turinga M nazywamy językiem generowanym przez maszynę M i oznaczamy przez L(M):
Zbiór wszystkich języków generowanych przez maszyny Turinga oznaczamy symbolem ZJMT i nazywamy rekursywnie przeliczalnymi.
Maszyne Turinga można przedstawić m in. za pomocą:
Przykład Maszyny Turinga

Przykład MT akceptującej słowa i MT obliczającej:

| MT | Języki |
|---|---|
| Maszyny Turinga Niedeterministyczne maszyny Turinga Wielotaśmowe maszyny Turinga Uniwersalna maszyna Turinga |
ZJRP zbiór języków rekursywnie przeliczalnych (rekurencyjnie przeliczalnych) |
| Właściwe MT - maszyny Turinga zatrzymująca się dla każdego słowa po skończonej ilości ruchów |
ZJRK Zbiór języków rekursywnych (rekurencyjnych) |
|
MT (automaty) liniowo ograniczone – maszyny Turinga w których <,> є Γ i głowica przesuwa się tylko między symbolami < i > wyznaczającymi początek i koniec słowa. |
ZJK Zbiór języków kontekstowych. |
Istnieje język formalny, który nie jest rekursywnie przeliczalnym, tzn. nie jest akceptowany przez żadną MT.# Zagadnienia na licencjat
Ciągiem nazywamy funkcję, której dziedziną jest zbiór liczb naturalnych lub jego skończony odcinek początkowy . Ciągiem liczbowym nazywamy ciąg, którego wyrazy są liczbami.
Liczbę nazywamy granicą ciągu nieskończonego , jeśli dla każdej liczby dodatniej istnieje taka liczba , że dla zachodzi nierówność:
Ciągiem zbieżnym (rozbieżnym) nazywamy ciąg, który posiada granicę (nie posiada granicy).
Jeśli ciąg posiada granicę to tylko jedną.
Każdy ciąg zbieżny jest ograniczony.
Przy założeniu, że ciągi i są zbieżne, zachodzą następujące wzory:
- (dla iloczynu i ilorazu też zachodzi)
Jeżeli ciąg jest zbieżny i , to .
Jeżeli ciąg jest zbieżny, to .
(Tw. o trzech ciągach): Jeśli , to ciąg jest zbieżny, przy czym .
Zmiana skończonej ilości wyrazów ciągu nie wpływa na jego zbieżność/granicę.
Podciąg ciągu zbieżnego jest zbieżny do tej samej granicy, co ciąg dany.
Po ludzku: Ciągi Cauchy'ego to takie ciągi, dla których odległości między wyrazami zmierzają do zera. Oznacza to, że wybierając dowolnie małą dodatnią liczbę rzeczywistą , można ustalić odpowiednio duży wskaźnik taki, że dowolne dwa wyrazy o wyższych wskaźnikach są odległe od siebie o mniej niż .
Ciąg jest zbieżny gdy jest ciągiem Cauchy’ego. (ale niekoniecznie odwrotnie).
Każdy ciąg Cauchy’ego jest ograniczony.
Macierzą (rzeczywistą) wymiaru m$\times$n, gdzie m, n , nazywamy prostokątną tablicę złożoną z m$\times$n liczb rzeczywistych ustawionych w m wierszach i n kolumnach
Suma/różnica
Niech macierz , . Sumą/różnicą nazywamy macierz , której elementy określone są wzorami
Zatem,
Iloczyn macierzy przez liczbę
Niech niech będzie dowolną liczbą rzeczywistą. Iloczynem macierzy przez liczbę nazywamy macierz której elementy określone są następująco:
dla {}, {}. Piszemy wtedy
Zatem
Iloczyn macierzy
Iloczyn macierzy jest możliwy jeśli macierz ma tyle samo kolumn co macierz ma wierszy. Iloczynem macierzy przez macierz nazywamy macierz taką, że:
Własności iloczynu macierzy:
Macierz transponowana
Niech
Wówczas
Rząd macierzy
Chcąc obliczyć rząd macierzy musimy znależć największą macierz, której wyznacznik jest różny od zera, wielkość tej niezerowej macierzy będzie szukaną wartością, czyli jeśli największą macierzą, której wyznacznik jest różny od zera jest macierz to rząd macierzy jest równy .
Przyklad
Aby obliczyć rząd macierzy zaczynamy od obliczenia wyznacznika największej macierzy czyli w tym przypadku
Następnie obliczamy macierze do momentu aż wyjdzie nam liczba różna od zera. Z macierzy można utowrzyć 16 macierzy w następujący sposób:
Jeżeli któraś z nich wyjdzie różna od zera to koniec obliczeń. Wystarczy że obliczając wyznacznik macierzy pierwszej wyjdzie nam liczba różna od zera - wtedy z automatu możemy powiedzieć, że rząd macierzy wynosi . Analogicznie jeżeli wszystkie wzory wyjdą na , to wtedy szukamy macierzy poprzez wykreślenie wiersza i kolumny analogicznie jak do kroków powyżej tak aby otrzymać macierz (czyli wykreślając po dwa wiersze i dwie kolumny).
Dla macierzy
operacja ta wygalda nastepująco:
Wyznacznik macierzy
np. Metoda Sarrusa
np. Rozwinięcie Laplace'a
Szukamy w macierzy wiersza lub kolumny która ma najwięcej zer (dla łatwiejszego obliczania). Na przykład:
Dla macierzy
Sytuacja wyglada tak:
Gdzie po równaniu pierwsza liczba to liczba wiersza i kolumny pomnożone przez do potegi razy macierz po wykreśleniu wiersza i kolumny . Następne dodajemy analogicznie.
Maceirz odwrotna $(A^{-1})$
Wzór:
gdzie:
Nie można obliczyć macierzy odwrotnej z macierzy osobliwej, czyli takiej której wyznacznik jest równy . Więc jeśli liczymy macierz odwrotną zawsze zaczynamy od obliczania wyznacznika macierzy, jeśli wyjdzie on to znaczy, że z danej macierzy nie można obliczyć macierzy odwrotnej.
Macierz odwrotna jest określona tylko dla macierzy kwadratowych, których wyznacznik jest .
Macierz odwrotna do macierzy kwadratowej to macierz spełniająca równanie , gdzie to macierz jednostkowa.
Jeśli macierz istnieje to macierz nazwyamy odwracalną, a jeśli macierz nie istnieje to macierz nazywamy nieodwracalną.
Jeśli macierz jest odwracalna to istnieje tylko jedna macierz odwrotna
Własności macierzy odwrotnej
Macierz nieosobliwa - macierz kwadratowa o wyznaczniku róznym od zera
Macierz symetryczna - macierz kwadratowa której wyrazy położone symetrycznie względem przekątnej głównej są równe, przykład:
Proces obliczania macierzy odwrotnej dla macierzy $3\times 3$
Podobnie jak wcześniej najpierw obliczamy wyznacznik macierzy :
Następnie obliczamy macierz dopełnień algebraicznych:
czyli
Więc:
Następnie obliczamy macierz transponowaną:
więc macierz odwrotna będzie miała postać:
Ślad macierzy
Ślad macierzy jest to suma elementów leżących na przekątnej danej macierzy. Ślad macierzy definujemy tylko dla macierzy kwadratowej. Ślad macierzy kwadratowej stopnia jest sumą elementów leżących na głównej przekątnej (diagonali). Ślad macierzy oznaczamy lub .
Mając macierz
obliczamy ślad macierzy w następujący sposób:
Własności śladu macierzy
Rozważmy układ równań liniowych o niewiadomych :
oraz macierz :
nazywać będziemy macierzą układu .
Macierz
nazywać będziemy macierzą wynikową.
Macierz
nazywać będzimy macierzą rozszerzoną układu .
Rozwiązaniem układu nazywać będziemy każdy -elementowy ciąg taki, że po podstawieniu do układu otrzymujemy równości:
Operacje elementarne
Za pomocą operacji elementarnych możemy przekształcać wiersze macierzy.
Możliwe operacje elementarne:
Metoda eliminacji Gaussa
Metoda eliminacji Gaussa polega na stosowaniu operacji elementarnych do macierzy rozszerzonej uładu równań liniowych tak, aby doprowadzić macierz rozszerzoną do postaci schodkowej.
Postać schodkowa:
Przykład:
Twierdzenie Cramera
Rozważamy układ równań liniowych o niewiadomych :
Jeżeli wyznacznik macierzy tego układu jest różny od zero to ten układ ma dokładnie jedno rozwiązanie postaci:
Natomiast macierz powstaje z macierzy poprzez zastąpienie -tej kolumny macierzy przez kolumnę macierzy wynikowej.
Przykład
Najpierw sprawdźmy czy wyznacznik macierzy układu jest rózny od zera
Oznacza to e układ ten ma dokladnie jedno rozwiązanie.
Musimy znalezc wzynacznik odpowiadajace kolejnym niewiadomym, czyli .
$A_1$
Wykreslamy pierwsza kolumne macierzy
W wolne miejsce wpisujemy kolumne macierzy wynikowej
Obliczamy wartosc
Teraz mozemy wyznaczyc niewiadoma
$A_2$
$A_3$
Podsumowujac otrzymalismy nastepujace rzowiazanie ukldau rownan:
Wniosek z twierdzenia Cramera
Prawem rachunku zdan lub tautologia nazywamy wyrażenie zbudowane ze zdań prostych i spójników, które zawsze jest zdaniem prawdziwym (niezależnie od wartości logicznych zdań prostych).
TAUTOLOGIA
W logice wartość logiczną zdania definiujemy jako 0, gdy zdanie to jest
fałszywe, zaś jako 1 , gdy zdanie to jest prawdziwe.
Symbolu 0 używamy również do oznaczenia dowolnego zdania fałszywego,
zaś symbolu 1 do oznaczenia dowolnego zdania prawdziwego.
Koniunkcja - to dwa zdania połączone spójnikiem logicznym .
Koniunkcja dwóch zdań jest prawdziwa jedynie wtedy, gdy oba zdania oraz są prawdziwe.
Alternatywa - to dwa zdania połączone spójnikiem logicznym .
Alternatywa dwóch zdań jest prawdziwa wtedy, gdy przynajmniej jedno ze zdań lub jest prawdziwe.
Implikacja - możemy odczytywać na wiele równoważnych sposobów:
Rownowaznosc - możemy odczytywać na wiele równoważnych sposobów:
Negacja - oznacza jednoargumentowy spójnik negacji, oznacza zdanie:
Najwazniejsze tautologie
Tautologia (z greki) - to wyrażenie, zdanie logiczne, które zawsze jest logiczne
Indukcja matematyczna – metoda dowodzenia twierdzeń o prawdziwości nieskończonej liczby stwierdzeń oraz definiowania rekurencyjnego. W najbardziej typowych przypadkach dotyczą one liczb naturalnych.
Aksjomat indukcji matematycznej
Jeśli jest podzbiorem , ktory spelnia:
to stanowi calosc , tzn .
Innymi slowy oznacza to ze jezeli dowiedziemy ze dany zbior posiada takie same wlasciwosci jak zbior (tj. jest dyskretny, posiada poczatkowy element oraz odlegosc miedzy nasepnymi dyskretnymi elementami jest zawsze taka sama) to element ten jest podzbiorem ale np przesunietym i powiekszonym o jakis skalar.
Przyklady

Permutacja zbioru -elementowego - to dowolny -wyrazowy ciąg utworzony ze wszystkich elementów tego zbioru.
Liczbę permutacji zbioru -elementowego możemy obliczyć ze wzoru:
Przyklady
Kombinacja pozwala policzyć na ile sposobów można wybrać elementów z -elementowego zbioru.
Wzór na kombinację jest następujący:
Kombinację zapisujemy krótko za pomocą Symbolu Newtona:
Przyklady
Przyjmijmy, że mamy dany zbiór elementów (np. zbiór liter). Wariacja z powtórzeniami pozwala na utworzenie ciągu z elementów tego zbioru, z tym, że dopuszcza powtarzanie elementów.
Wzór na wariację z powtórzeniami jest następujący:
Przyklady
Przykładami taki słów są: .
Na każde z miejsc możemy wybrać jedną z liter, zatem wszystkich możliwości mamy:
Przykładami taki słów są: .
Na każde z miejsc możemy wybrać jedną z liter, zatem wszystkich możliwości mamy:
Przyjmijmy, że mamy dany zbiór elementów (np. zbiór liter). Wariacja bez powtórzeń pozwala na utworzenie ciągu z elementów tego zbioru, z tym, że nie dopuszcza powtarzania elementów. Wzór na wariację bez powtórzeń jest następujący:
Przyklady
Mamy do dyspozycji cyfr: .
Przykładowymi kodami o różnych cyfrach są: . Wszystkich takich wariacji bez powtórzeń jest:
Definicja
Zakładamy, że przestrzeń zdarzeń elementarnych \OmegaΩ ma skończoną liczbę zdarzeń elementarnych i każde z nich jest jednakowo prawdopodobne. Wtedy prawdopodobieństwo definiujemy następująco:
Dla dowolnego
Kilka wyjaśnień:
Krótko: prawdopodobieństwo uzyskania jakiegoś wyniku to liczba sprzyjających wyników przez liczbę wszystkich możliwych wyników. Zatem chcąc obliczyć prawdopodobieństwo zajścia pewnego zdarzenia:
Własności prawdopodobieństwa
Prawdopodobieństwo dowolnego zdarzenia losowego A jest zawsze liczbą z przedziału ⟨0;1⟩.
Prawdopodobieństwo zdarzenia pewnego jest równe 1.
Prawdopodobieństwo zdarzenia niemożliwego jest równe 0.
Przydatne wzory
Prawdopodobieństwo zdarzenia przeciwnego:
Prawdopodobieństwo sumy zdarzeń
Prawdopodobieństwo warunkowe
Prawdopodobieństwo warunkowe zajścia zdarzenia A pod warunkiem zajścia zdarzenia B liczymy ze wzoru:
Prawdopodobieństwo całkowite
Jeżeli zdarzenia są parami rozłączne oraz mają prawdopodobieństwa dodatnie, które sumują się do jedynki, to dla dowolnego zdarzenia A zachodzi wzór:
Wzór Bayesa
Jeżeli zdarzenia są parami rozłączne oraz mają prawdopodobieństwa dodatnie, które sumują się do jedynki, to dla dowolnego zdarzenia A zachodzi wzór:
Schemat Bernoulliego
W schemacie Bernoulliego prawdopodobieństwo uzyskania k sukcesów w n próbach można obliczyć ze wzoru:
Klasyczny komputer o architekturze podanej przez von Neumana składa się z trzech podstawowych bloków:
Struktura logiczna komputera
Po załadowaniu programu do pamięci komputera może on zostać w dowolnej chwili wywołany przez operatora. W tym celu musi on wydać polecenie rozpoczęcia wykonywania tego programu przez wymuszenie odczytania pierwszego polecenia tego programu. W tym celu należy spowodować, aby procesor wysłał do pamięci odpowiedni adres. Dalsze polecenia są umieszczone w pamięci kolejno, więc będą odczytywane przez procesor automatycznie. Wykonywanie programu polega, więc na pobieraniu z pamięci kolejnych poleceń i odpowiednich dla tych poleceń argumentów. Argumenty rozkazu mogą być:
- w pamięci i wówczas rozkaz musi zawierać adres miejsca w pamięci, gdzie one się znajduje,
- w rejestrach procesora i wówczas rozkaz musi wskazywać adres odpowiedniego rejestru,
- w samym rozkazie i wówczas programista umieszcza je w odpowiednio w kodzie programu.
W czasie wykonywania programu procesor odczytuje kolejne rozkazy, które następnie musi rozpoznać (dekodować). Po zdekodowaniu rozkazu, w zależności od treści tego rozkazu, procesor podejmuje odpowiednią akcję. Akcja ta polega na wykonaniu odpowiedniej operacji. Między innymi, z treści rozkazu, może wynikać konieczność odczytania argumentów dla niego.
Jeżeli argument znajduje się, w pamięci, to dalsza akcja polega na odczytaniu adresu tego argumentu. Jeżeli adres ten programista umieścił w kodzie programu, to odczytane będzie następne słowo(a) z kodu programu stanowiące ten adres. Jeżeli argument znajduje sic, w rejestrze procesora, to rozkaz musi wskazać, w którym z rejestrów procesora znajduje się adres. Po skompletowaniu całej instrukcji procesor wykonuje ją, a dalej pobiera następny rozkaz i cała akcja się powtarza.

(schemat czytamy od gory - strzalka znika z prawej strony i pojawia sei po lewej dolnej stronie)
Na schemacie:
Typowa organizacja procesora to blok rejestrów, blok ALU i dekoder kodu rozkazowego. Najważniejszym układem procesora jest blok arytmetyczno logiczny ALU wykonujący operacje na argumentach z dwóch rejestrów A i B. Cykl pracy procesora rozpoczyna się od wysłania do pamięci adresu rozkazu. Adres ten znajduje się, w rejestrze LR zwanym licznikiem rozkazów.
Odczytywany z pamięci rozkaz zostaje przesłany do rejestru rozkazów RR. Zawartość tego rejestru jest dekodowana i blok ALU zostaje odpowiednio wysterowany do wykonania danej operacji. Zarówno rozkazy procesora jak i argumenty tych rozkazów są przedstawiane w komputerze w postaci słów binarnych, tj. kodowane w zapisie dwójkowym. (dlugosc slowa zawsze jest taka sama i odpowiada bitowosci komputera tj. 8-bitow, 16-bitow, 32-bity itd)

Pamięć jest podzielona na komórki, w których są przechowywane pojedyncze słowa (bajty). Każda komórka ma swój adres i podanie tego adresu na wejście adresowe pamięci umożliwia dostęp do danej komórki, czyli odczyt lub zapis. W zależności od sygnału O (odczyt) / Z (zapis) pamięć jest odczytywana lub zapisywana.
Wielkość takiej pamięci nazywana jest pojemnością pamięci i jest oznaczana przez (liczba pamiętanych słów przez długość słowa). W jednym cyklu pracy takiej pamięci można odczytać lub zapisać tylko słowo 8-bitowe. W przypadku, gdy długość rozkazu lub argumentu jest większa, to jest on zapisywany w dwóch (lub więcej) komórkach pamięci. Cykl instrukcyjny składa się z 4 faz:
- fazy pobrania rozkazu
- dwóch faz pobrania argumentów rozkazu
- fazy zapisu wyniku do pamięci.
Pozycyjny system liczbowy - to system liczbowy ktory opiera sie o pewien skonczony zestaw cyfr tego systemu. Kazda liczba w systemie pozycyjnym zostaje przedstawiona jako ciag cyfr tego systemu gdzie kazda nastepna cyfra na indeksie () gdzie to ilosc cyfr tego systemu, przedstawia wartosc .
Wzor:
Przyklady
Zamiana z na $(10)$
Zamiana z na $(2), (16)$
Zamiana z na $(16)$

Zamiana z na $(2)$

Zastowosawnie systemu dwojkowego
System dwojkowy oznaczany wykorzystywany jest jako glowny podloze wszystkich obliczen komputerow elektronicznych. Zostal wybrany na system pozycyjny komputerow poniewaz moze przedstawiac brak napieca a napiecie na danej sciezce, w danej komorce pamieci lub nosniku danych co sprawia ze jest to system bardzo prosty poniewaz nie wymaga pomiaru poziomu napiecia pradu przeplywajacego przez komponent w celu uzyskania danyhc z tego komponentu.
Zastosowanie systemu szesnastkowego
System szesnastkowy oznaczany wykorzystywany jest jako roziwniecie systeu dowjkowego. Dzieki wiekszej podstawie tego systemu, liczby zapisywane w nim sa bardziej kompaktowe i dzieki temu bardziej czytelne.
Komputerowa reprezentacja liczb calkowitych z przedzialu od do (przedzial zalezy od standardu), gdzie n jest liczba bitów w slowie maszynowym, zapisywanych w kodzie uzupelnien do dwóch. Zakres liczb 16-bitowych w a.s. (komputery PC) miesci sie w przedziale . Przekroczenie zakresu liczb powoduje nadmiar. W arytmetyce stalopozycyjnej sa wykonywane cztery podstawowe dzialania (+, -, * i /), przy czym stosuje sie dzielenie calkowite.
Reprezentacja liczby rzeczywistej zapisanej za pomocą notacji naukowej. Ze względu na wygodę operowania na takich liczbach, przyjmuje się ograniczony zakres na mantysę i cechę – nazwy te mają w matematyce znaczenie podane w artykule podłoga i sufit, a w niniejszym artykule inne, powszechne w informatyce. Powoduje to, że reprezentacja liczby rzeczywistej jest tylko przybliżona, a jedna liczba zmiennoprzecinkowa może reprezentować różne liczby rzeczywiste z pewnego zakresu.
Stalopozycjne (calkowite)

Stalopozycjne (rzeczywiste)

Stalopozycjne (rzeczywiste cd.)

Zmiennopozycyjne
## 11. System operacyjny. Postrzeganie systemu operacyjnego przez warstwę oprogramowania użytkowego.
Źródło: wykład "Wprowadzenie do systemów operacyjnych"
System operacyjny jest warstwą oprogramowania operującą bezpośrednio na sprzęcie, której celem jest zarządzanie zasobami systemu komputerowego i stworzenie użytkownikowi środowiska łatwiejszego do zrozumienia i wykorzystania.

System operacyjny pośredniczy pomiędzy użytkownikiem a sprzętem, dostarczając wygodnego środowiska do wykonywania programów. Użytkownik końcowy korzysta z programów (aplikacji), na potrzeby których przydzielane są zasoby systemu komputerowego. Przydziałem tym zarządza system operacyjny, dzięki czemu można uzyskać stosunkowo duży stopień niezależności programów od konkretnego sprzętu oraz odpowiedni poziom bezpieczeństwa i sprawności działania.
Nie ma precyzyjnego określenia, które składniki wchodzą w skład systemu operacyjnego jako jego części.

W ogólnym przypadku w strukturze systemu operacyjnego wyróżnia się jądro oraz programy systemowe, które dostarczane są razem z systemem operacyjnym, ale nie stanowią integralnej części jądra. Jądro jest zbiorem modułów, które ukrywają szczegóły sprzętowej realizacji systemu komputerowego, udostępniając pewien zestaw usług, wykorzystywanych między innymi do implementacji programów systemowych.
Z punktu widzenia kontaktu z użytkownikiem istotny jest interpreter poleceń, który może być częścią jądra lub programem systemowym (np. w systemie UNIX). Interpreter wykonuje pewne polecenia wewnętrznie, tzn. moduł lub program interpretera dostarcza implementacji tych poleceń. Jeśli interpreter nie może wykonać wewnętrznie jakiegoś polecenia, uruchamia odpowiedni program (tzw. polecenie zewnętrzne), jako odrębny proces.
Programy systemowe (programy użytkowe systemu):
Zadania systemu operacyjnego:
Proces - uruchomiony program. Jeden program to może być wiele procesów, bo np. uruchomimy wiele razy ten jeden program. Każdy proces jest identyfikowany przez numer PID.
W systemie operacyjnym każdy proces posiada proces nadrzędny (rodzica), z kolei każdy proces może, poprzez wywołanie funkcji systemu operacyjnego, utworzyć swoje procesy potomne. W ten sposób tworzy się swego rodzaju drzewo procesów.
W skład procesu wchodzi:
W trakcie ładowania procesu do pamięci system operacyjny tworzy stos (stack) i stertę (heap).
Stos – do przechowywania zmiennych, parametrów funkcji, adresów powrotu. Sterta – do przechowywania dynamicznie alokowanych danych, np. listy
Stany procesu:
Czasami może być konieczne współbieżne wykonywanie pewnych fragmentów programu. Aby to zrealizować, program może zażądać utworzenia określonej liczby wątków, wykonujących wskazane części programu. Ta cecha systemu operacyjnego to wielowątkowość. W jednym procesie może być kilka wątków. Każdy wątek ma swój własny stos (posiada swoje zmienne lokalne)
Cecha systemu operacyjnego umożliwiająca równoczesne wykonywanie więcej niż jednego procesu (programu).
Jest jak policjant na skrzyżowaniu, który wskazuje, które auta mogą teraz przejechać przez skrzyżowanie. Jest to część systemu operacyjnego przełączająca procesy według polityki szeregowania zadań. Do jego zadań należy m.in. przełączanie kontekstu.
Planista krótkoterminowy ustala wartość priorytetu. Wybiera proces o najwyższym priorytecie do wykonania.

Możliwe jest zagłodzenie procesu, gdy dany proces nie jest w stanie zakończyć działania, ponieważ nie ma dostępu do procesora lub innego współdzielonego zasobu. Występuje najczęściej na skutek niewłaściwej pracy algorytmu szeregowania lub nadmiernego obciążenia systemu.
Zdarza się również tzw. zakleszczenie, czyli blokada wzajemna. Powstaje wtedy, gdy wiele zadań w tym samym czasie konkuruje o wyłączny dostęp do zasobów. Zakleszczenie:

Iteracja - czynność powtarzania (najczęściej wielokrotnego) tej samej instrukcji (albo wielu instrukcji) w pętli.
Rekurencja to w logice, programowaniu i w matematyce odwoływanie się np. funkcji lub definicji do samej siebie.
Najwięcej problemów związanych z rekurencją wiąże się z ograniczeniami stosu wywołań, a właściwie jego pojemności. Na stosie są odkładane kolejne wywołania danej metody i dopiero gdy dojdziemy do ostatniego elementu dane te są zbierane – bardzo łatwo więc o sytuację, gdy po prostu stos przepełnimy.
Silnia iteracyjnie: n! = 1 * 2 * 3...* n
Silnia rekurencyjnie: n! = n * (n-1)!
Ciąg Fibonacciego
Definicja: dla mamy
natomiast wyrazy 1 i 0 przyjmują wartość 1.
Fibonacci rekurencyjnie:
function FibR(n)
begin
if ( n=0 or n=1) then {
return 1
}
return FibR(n-1) + FibR(n-2)
end
Fibonacci iteracyjnie:
function FibI(n)
begin
tmp :=0 // zmienna tymczasowa (pomocnicza)
x := 1 // wyraz n-1
y := 1 // wyraz n-2
for i:=1 to n-1 step 1 {
tmp := y // zapamiętaj wyraz n-2
y := y+x // przesuń wyraz n-2 na kolejną wartość ci¡gu
x := tmp // przesuń wyraz n-1 na kolejną wartość ci¡gu
// czyli na warto±¢ wyrazu n-1 przed jego
// przesunięciem
}
return x
end
I mean..come on ;-;
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
Note: The default keyword must be used as the last statement in the switch, and it does not need a break. default can be the first statement on the list, but it makes no sense since only this statement will be executed.
break and default keywords are optional.
Without a break statement, every statement from the matched case label to the end of the switch, including the default, is executed.
| Condition | Action |
|---|---|
| Converted value matches that of the promoted controlling expression. | Control is transferred to the statement following that label. |
| None of the constants match the constants in the case labels; a default label is present. | Control is transferred to the default label. |
| None of the constants match the constants in the case labels; no default label is present. | Control is transferred to the statement after the switch statement. |
Podprogramy – wydzielona część programu wykonująca określony zbiór instrukcji, posiadająca swoją nazwę i stanowiąca pewną odrębną całość. Ich nazwy powinny informować o ich wyniku działania.
Ogólnie przyjęta konwencja (w przypadku C++) typ_rezultatu nazwa_funkcji( lista parametrów formalnych); na przykład:
bool isPrime(int);
Podprogramy dzielą się na dwa rodzaje:
Innym szczególnym przypadkiem są metody – funkcje, które są własnością klasy lub obiektu. Bez ich istnienia nie można się do nich odwołać.
W niektórych językach programowania nie istnieje powyższy podział.
Jeżeli chodzi o C++, formalnie procedury nie istnieją, jednak łatwo się domyślić, że ustawiając jako typ rezultatu void możemy utworzyć coś na jej wzór.
Przekazywanie parametrów do podprogramów odbywa się głównie na dwa sposoby:
int addOne(int number) {
return number++; //przez wartość
}
int addOne(int &number) {
return number++; //przez referencję
}
Programowanie strukturalne – paradygmat programowania opierający się na podziale kodu źródłowego programu na procedury i hierarchicznie ułożone bloki z wykorzystaniem struktur kontrolnych w postaci instrukcji wyboru i pętli. Język programowania zgodny z paradygmatem programowania strukturalnego nazywa się językiem strukturalnym.
Struktury kontrolne:
Programowanie obiektowe – paradygmat programowania, w którym programy definiuje się za pomocą obiektów – elementów łączących stan i zachowanie. Obiektowy program komputerowy wyrażony jest jako zbiór takich obiektów, komunikujących się pomiędzy sobą w celu wykonywania zadań.
| Programowanie strukturalne |
|
|
| Programowanie obiektowe |
|
|
aka enkapsulacja
Polega na ukrywaniu informacji - ukrywanie pewnych danych składowych lub metod w obiektach danej klasy tak, aby były one dostępne tylko dla metod wewnętrznych danej klasy lub dla metod z klas z nią zaprzyjaźnionych.
Z pełną enkapsulacją mamy do czynienia wtedy gdy dostęp do wszystkich pól w klasie jest możliwy tylko i wyłącznie poprzez metody, lub inaczej: gdy wszystkie pola w klasie znajdują się w sekcji prywatnej (lub chronionej)
Klasa to definicja obiektu, zawierająca stan obiektu, określony wartościami pól, oraz możliwe zachowanie, określone dostępnymi metodami.
Obiekt to utworzony egzemplarz (instancja) określonej klasy, który posiada własny, indywidualny stan i zbiór zachowań.
Metoda to funkcja lub procedura, skojarzona z ogółem klasy lub poszczególnymi jej obiektami; określa możliwe zachowania
Pole (Właściwość) to zmienna dowolnego typu, skojarzona z ogółem klasy lub poszczególnymi jej obiektami; określa aktualny stan obiektu
Dziedziczenie to mechanizm definiowania nowej klasy na bazie już istniejącej, wzbogacając ją o nowe pola, metody lub zmieniając zakres ich widoczności.
Struct - wszystkie składowe (pola i metody) są domyślnie publiczne
Class - wszystkie składowe (pola i metody) są domyślnie prywatne
Metoda
class MyClass {
void privateMethod(); //deklaracja w klasie
public:
void publicMethod() { //definicja w klasie
//donothing;
};
}
Definicja klasy musi zawierać przynajmniej deklarację metody
Definicja metody, często dla czytelności kodu, jest umieszczana poza klasą
void MyClass::privateMethod() { //definicja poza klasą
//this method is depressed
}
struct Obj {
int a, b; //od C++11 możliwa inicjalizacja w klasie, np.
//int a = 0;
Obj(int _a = 0, int _b = 0){ //konstruktor
a = _a;
b = _b;
}
};
{
Obj x, y(1), z(1,2), v = 3, u = {3,4}; //wywołania konstruktora
Obj t[5], *s = new Obj, *p = new Obj[3]; //wielokrotne
}
Konstruktor domyślny:
struct Obj {
int a, b;
Obj(){ //konstruktor domyślny
a = 0;
b = 0;
}
Obj()=default;//konstruktor domyślny bez inicjalizacji(C++11)
};
{
Obj x, t[5]; //wywołania konstruktora domyślnego
Obj *s = new Obj, *p = new Obj[3]; //tu też
}
struct Obj {
int a, b;
Obj(int _a, int _b = 0){ //1- lub 2-parametrowy konstruktor
a = _a;
b = _b;
}
};
{
Obj y(1), z(1, 2); //wywołania konstruktora
Obj x; //brak konstruktora domyślnego – błąd kompilacji!
}
Konstruktor kopiujący:
struct Obj {
int a, b;
... //inne konstruktory łącznie z domyślnym
Obj(const Obj &o){ //konstruktor kopiujący
a = o.a;
b = o.b;
}
};
{
Obj x;
Obj y(x), z = x; //wywołania konstruktora kopiującego
}
struct Obj {
int a, b;
... //konstruktory łącznie z domyślnym
~Obj(){...} //destruktor
~Obj()=default; //destruktor domyślny (C++11)
};
{
Obj x, *p = new Obj; //wywołania konstruktora
delete p; //jawne wywołanie destruktora (obiekt *p)
} //niejawne wywołanie destruktora (obiekt x)
Destruktory obiektów:
{
Obj x, *p = new Obj, z;
{ Obj y; } //destruktor dla obiektu y
delete p; //destruktor dla obiektu *p
} //destruktor dla obiektu z i dalej dla x
Kiedy wywoływany jest destruktor?
Dla każdej klasy kompilator tworzy automatycznie (o ile nie zdefiniowano ich jawnie) następujące metody:
struct Obj {
int a, b;
};
{
Obj x; //konstruktor domyślny, atrybuty są przypadkowe
Obj y = x; //konstruktor kopiujący
x = y; //operator przypisania
} //destruktor domyślny obiektów y i x
W programowaniu obiektowym jest to obiekt pozwalający na sekwencyjny dostęp do wszystkich elementów lub części zawartych w innym obiekcie, zwykle kontenerze lub liście.
Podstawowym celem iteratora jest pozwolić użytkownikowi przetworzyć każdy element w kolekcji bez konieczności zagłębiania się w jej wewnętrzną strukturę. Np.: przejść do kolejnego elementu, na koniec na początek. Użytkownik nie musi np. zajmować się tym, że odwoła się do nieistniejącego elementu.
W C++ iteratory są szeroko wykorzystywane w bibliotece STL. Iteratory stosuje się zwykle w parach, gdzie jeden jest używany do właściwej iteracji, zaś drugi oznacza koniec kolekcji.
Iteratory tworzone są przez odpowiadający im kontener standardowymi metodami, takimi jak begin() i end(). Iterator zwrócony przez begin() wskazuje na pierwszy element, podczas gdy iteratorzwrócony przez end() wskazuje na pozycję za ostatnim elementem kontenera.
int main() {
vector<int> ar = { 1, 2, 3, 4, 5 };
// Declaring iterator to a vector
vector<int>::iterator ptr;
// Displaying vector elements using begin() and end()
cout << "The vector elements are : ";
for (ptr = ar.begin(); ptr < ar.end(); ptr++)
cout << *ptr << " ";
return 0;
}
Output:
The vector elements are : 1 2 3 4 5
Just in case: przeciążenie operatorów slajd 7+ (Cybula) oraz slajd 8+ (Wardowski).
Selektory
x.set(4, 4.5);
INSERT INTO TABLE osoby VALUES (’Jan’, ’Kowalski’);
SELECT imie FROM osoby WHERE nazwisko = ’Kowalski’;
UPDATE osoby SET imie = ’Adam’;
DELETE FROM osoby WHERE nazwisko = ’Kowalski’;
CREATE TABLE osoby (imie VARCHAR(50), nazwisko VARCHAR(50));
Jest to mechanizm umożliwiający tworzenie nowych klas na podstawie klasy już istniejących w ten sposób, że nowa klasa przejmuje (dziedziczy) wszystkie metody drugiej klasy.
Zalety:
Klasa oryginalna, na podstawie której tworzymy nową, nazywamy klasą macierzystą.
Klasa, która dziedziczy funkcjonalność innej klasy nazywamy klasą potomną.
class Pracownik {
private:
enum {ILE = 20};
char imie[ILE];
char nazwisko[ILE];
char stanowisko[ILE];
double pensja;
public:
Pracownik(const char*, const char*, const char*, double p);
void wypiszDane() const;
void ustawPensja(double);
double getPensja() const;
};
class Dyrektor : public Pracownik {
private:
double dodatekFunkcyjny;
public:
Dyrektor(double, const char* i, const char*, const char*, double p);
Dyrektor(double dF, const Pracownik &);
double getDodatekFunkcyjny() {return dodatekFunkcyjny;}
void setDodatekFunkcyjny(double dF) {dodatekFunkcyjny = dF;}
};
Dwukropek oznacza, że klasa Dyrektor powstała z klasy Pracownik, która tutaj stanowi publiczną klasę macierzystą (dziedziczenie publiczne). Obiekt klasy potomnej zawiera wszystkie pola składowe i metody klasy macierzystej. Gdy dziedziczenie jest publiczne, to wszystkie składowe publiczne klasy macierzystej stają się składowymi publicznymi klasy potomnej. Dostęp do odziedziczonych prywatnych składowych jest możliwy poprzez odziedziczone publiczne lub chronione metody klasy macierzystej.
Obiekt klasy potomnej
Obiekt klasy Dyrektor ma następujące cechy:
W klasie potomnej powinny być zdefiniowane własne konstruktory, które dostarczają danych
zarówno dla nowych pól jak i odziedziczonych.
Klasa potomna może być uzupełniona o dodatkowe pola składowe i metody.
Konstruktory klasy potomnej
Klasa potomna nie może korzystać z prywatnych składowych klasy macierzystej, musi więc odwoływać się do nich za pomocą publicznego interfejsu klasy macierzystej. W konsekwencji konstruktory klasy potomnej mogą wykorzystywać konstruktory klasy macierzystej.
Podczas tworzenia obiektu klasy potomnej tworzony jest najpierw obiekt klasy macierzystej. Aby wywołać odpowiedni konstruktor klasy macierzystej, wykorzystuje się tzw. listę inicjatorów konstruktora (listę inicjalizacyjną).
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p) : Pracownik (i,n, s, p) {
dodatekFunkcyjny = dF;
}
//konstruktor bez listy inicjalizacyjne
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p = 0) {
dodatekFunkcyjny = dF;
}
//powyższy konstruktor jest równoważny poniższemu:
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p) : Pracownik() {
dodatekFunkcyjny = dF;
}
//konstruktor powodujący wywołanie konstruktora kopiującego:
Dyrektor::Dyrektor(double dF, const Pracownik & p) : Pracownik(p) {
dodatekFunkcyjny = dF;
}
Podczas likwidacji obiektu klasy potomnej w pierwszej kolejności wywoływany jest destruktor tej klasy, a następnie wywoływany jest destruktor klasy macierzystej.
Dyrektor anna(500,”Anna”, ”Lis”, ”Dyrektor”, 3000);
anna.wypiszDane();
Pracownik* p1;
p1 = &anna;
p1->wypiszDane();
Pracownik& p2 = anna;
p2.wypiszDane();
p1->setDodatekFunkcyjny(500); //błąd!!!, p1 wskazuje na obiekt klasy macierzystej
Pracownik p3();
Dyrektor& d1 = p3; //błąd!!!
Dyrektor* d2 = &p3; //błąd!!!
Inicjalizacja obiektu klasy macierzystej za pomocą obiektu klasy potomnej
Dyrektor dyr(300, ”Jan”, ”Kowalski”, ”Dyrektor”, 3000);
Pracownik p(dyr);
W powyższej sytuacji działa konstruktor kopiujący klasy macierzystej:
Pracownik(const Pracownik&);
Przypisanie obiektu klasy potomnej do obiektu klasy macierzystej
Dyrektor dyr(300, ”Jan”, ”Kowalski”, ”Dyrektor”, 3000);
Pracownik p;
p = dyr;
W powyższej sytuacji działa w sposób niejawny operator przypisania:
Pracownik& operator=(const Pracownik&);
W C++ wyróżniamy trzy rodzaje dziedziczenia:
Dziedziczenie - kontrola dostępu:

MyAbstractClass abclass; //błąd!
MyAbstractClass * p; //OK
Dziedziczenie wielokrotne zazwyczaj prowadzi do niejednoznaczności wywołań funkcji.
Najlepszym rozwiązaniem jest przedefiniowanie wszystkich metod w klasie, która dziedziczy z
wielu klas macierzystych. W przedefiniowanych metodach przeważnie wskazujemy w sposób
jawny, które wersje metod chcemy wywołać.
Mechanizm polegający na tym, że jedna metoda może występować w wielu różnych postaciach w zależności od kontekstu jej wywołania nazywamy polimorfizmem.
W celu wdrożenia polimorficznego działania dziedziczenia publicznego stosujemy:
Aby odpowiednia wersja metody została wywołana należy przed deklaracją metody umieścić słowo virtual. W definicji słowo virtual pomijamy.
virtual double getPensja(); //deklaracja metody dla klasy Dyrektor
...
double getPensja() { //definicja metody
return Pracownik::getPensja() + dodatekFunkcyjny;
}
W przypadku poprzedzenia deklaracji słowem virtual, odpowiednia wersja metody zostanie wywołana w oparciu o typ obiektu, do którego odwołuje się referencja lub wskaźnik.
Dyrektor anna;
Pracownik janek;
Pracownik& p1 = anna;
Pracownik& p2 = janek;
p1.getPensja(); //wywołana metoda Dyrektor::getPensja();
p2.getPensja(); //wywołana metoda Pracownik::getPensja();
W przypadku, gdy metoda przedefiniowana nie jest poprzedzona w części deklaracyjnej słowem virtual, wówczas sposób działania metody opiera się na typie referencji, a nie na typie obiektu.
Dyrektor anna;
Pracownik janek;
Pracownik& p1 = anna;
Pracownik& p2 = janek;
p1.getPensja(); //wywołana metoda Pracownik::getPensja();
p2.getPensja(); //wywołana metoda Pracownik::getPensja();
Zazwyczaj dobrą praktyką jest poprzedzanie w klasie macierzystej słowem virtual deklaracje tych metod, które są przedefiniowane w klasie potomnej. Zabieg ten pozwala wybrać odpowiednie wersje metod, na podstawie obiektu, na rzecz którego są one wywoływane, a nie na postawie referencji lub wskaźnika.
Poprzedzenie destruktorów słowem virtual powoduje, że podczas destrukcji obiektu zostanie wywołany odpowiedni kod destruktora.
Wiązanie nazwy funkcji polega na określeniu odpowiedniego bloku wykonywalnego (w kodzie skompilowanym), który ma zostać użyty.
Wiązanie statyczne to wiązanie, które jest realizowane podczas kompilacji kodu źródłowego.
Wiązanie dynamiczne, to odpowiedni mechanizm, który pozwala wybrać odpowiednią metodę wirtualną podczas działania programu.
Uwaga Wiązanie dynamiczne zachodzi wówczas, gdy odpowiednie metody wywoływane są przez wskaźniki lub referencje.
Polimorfizm statyczny jest często implementowany za pomocą szablonów. Jest on nieograniczony, bo interfejsy typów uczestniczących w polimorfizmie nie są z góry określone.
Szablony służą do tworzenia ogólnych deklaracji klas (lub funkcji). W ten sposób realizowana jest koncepcja tzw. typów sparametryzowanych. Typ jest argumentem przekazywanym do ogólnego wzorca klasy lub funkcji.
Szablony pozwalają na wielokrotne wykorzystanie istniejącego kodu źródłowego struktury danych dla wielu wersji tej struktury z tym samym interfejsem, ale różnymi typami dla wewnętrznych komponentów (programowanie generyczne/uogólnione, struktury parametryzowane)
template <typename T>
class Punkt {
private:
T x, y;
public:
Punkt();
Punkt(T,T);
T getX();
T getY();
void setXY(T,T);
void wypisz();
};
template <typename T>
Punkt<T>::Punkt() {
x = y = 0;
}
template <typename T>
T Punkt<T>::getX() {
return x;
}
...
Chcąc wygenerować klasę na podstawie zdefiniowanego szablonu należy jawnie określić typ parametru (tzn. dokonać jawnej konkretyzacji typu).
#include <iostream>
#include "Punkttp.h"
using namespace std;
int main() {
Punkt<int> p(3,2);
cout << p.getX();
Punkt<double> z(3.2,2.1);
z.setXY(5.01,3);
return 0;
}
Konkretyzując klasę możemy użyć zarówno typu wbudowanego jak i obiektu jakiejś klasy.
W języku C++ możemy używać szablony, które posiadają więcej niż jeden argument typu. Korzystając z tej możliwości możemy utworzyć klasę do przechowywania dwóch elementów różnych typów.
template <typename T1, typename T2>
class Pair {
private: T1 x, T2 y;
public:
T1 & first(const T1 & f) {x = f; return x;};
T2 & second(const T2 & s) {y = s; return y;};
T1 first() const {return x;}
T2 second() const {return y;}
Pair(const T1 & f, const T2 & s) : x(f), y(s) {}
Pair(){}
};
```## 21. Listy i drzewa oraz ich zastosowania. Stosy i kolejki.
<a href="<link_to_resource_local_or_online_here>"></a><b></b>
__Listy__
Lista to ciąg elementów, gdzie każdy zawiera atrybuty: ***key***, ***next*** oraz ***previous***. Wartość każdego z tych elementów odczytujemy przez ***key[x]***. Listy reprezentujemy poprzez obiekt, zawierający atrybuty ***head*** oraz ***tail***, wskazujące odpowiednio na początek i koniec listy.
Listy dzielimy na 3 typy:
1. listy jednokierunkowe
2. Listy dwukierunkowe
3. Listy cykliczne
<br />
W liście ***jednokierunkowej*** każdy z elementów wskazuje na element następny, czyli dla każdego x, next[x] wskazuje na kolejny. Ostatni element listy wskazuje na pusty element ***NIL***.

<br />
W liście ***dwukierunkowej*** każdy element zawiera trzy atrybuty. Oprócz atrybutu next zawiera także *previous* wskazujący na poprzedni element listy. Na pusty element ***NIL*** wskazuje zarówno pierwszy jak i ostatni element listy.

<br />
Listą ***cykliczną*** nazywamy listę, w której ostatni element **zamiast wskazywać** na pusty element **NIL**, wskazuje na pierwszy element listy. **Nie występują** tutaj atrybuty **head i tail**.
<br />

<br />
__Stos__
Stos to liniowa struktura danych, gdzie elementy przetwarzane są w kolejności od tego, który pojawił się najpóźniej (jest na górze stosu) do tego, który pojawił się na samym początku (na dole stosu).
Poszczególne elementy można przeglądać, lecz by pobrać element znajdujący się poniżej, trzeba pobrać ze stosu wszystkie elementy znajdujące się nad nim.
W algorytmach stos reprezentowany jest przez strukturę **LIFO (Last In First Out)**.
<br />
__Kolejka__
Kolejka jest strukturą działającą przeciwnie do stosu. Dane są przetwarzane w kolejności ich pojawienia się, tzn.: zaczynając od tego, który pojawił się na początku, kończąc na tym, który znalazł się na samym końcu.
W algorytmach kolejka reprezentowana jest poprzez strukturę ***FIFO (First In First Out)***.
<br />
__Drzewa__
Drzewo składa się z elementów , które posiadają **trzy** atrybuty: ***key***, ***left*** oraz ***right***.
Drzewo reprezentowane jest przez obiekt z atrybutem ***root (korzeń)***. Kolejne elementy są jego potomkami.

W informatyce drzewo wykorzystywane jest do budowy ***drzew decyzyjnych***, które są podstawą działania takich algorytmów jak ***min-max*** (wyznaczanie optymalnych ruchów).
## 22. Grafy i metody ich przeszukiwania. Zastosowania.
__Grafy__
**Graf** To struktura matematyczna służąca do przedstawiania i badania relacji między obiektami. W uproszczeniu **Graf to zbiór wierzchołków, które mogą być połączone krawędziami w taki sposób, że każda krawędź kończy się i zaczyna w którymś z wierzchołków**.
<br />
***Grafem nieskierowanym*** nazywamy parę **G=(V, E)**, gdzie **V** jest pewnym zbiorem skończonym zwanym **zbiorem wierzchołków grafu G**.
Natomiast **E** jest zbiorem nieuporządkowanych par **{u, v}** gdzie ***u, v $\isin$ V*** oraz ***u != v***.
Zbiór **E** nazywamy zbiorem krawędzi grafu **G**.

Jeśli ***{u, v}*** jest krawędzią grafu nieskierowanego **G**, to mówimy, że ***{u, v}*** jest ***incydentna*** z wierzchołkami **u** i **v**.
**Stopniem** wierzchołka w grafie nieskierowanym nazywamy ***liczbę incydentnych z nim krawędzi***. Pętlę liczymy za 2.
<br />
***Grafem skierowanym*** nazywamy parę ***G=(V, E)***, gdzie **V** jest pewnym zbiorem skończonym zwanym **zbiorem wierzchołków grafu G**.
Natomiast **E** - zbiór krawędzi grafu **G**.
**G** - zbiór uporządkowanych par ***{u, v}** oznaczanych **(u, v)**, gdzie ***u, v $\isin$ V***

**Stopniem** wierzchołka w grafie skierowanym nazywamy **sumę liczby krawędzi wchodzących do wierzchołka i wychodzących z tego wierzchołka**
<br/>
**Rząd grafu** - liczba wierzchołków w grafie.
**Rozmiar grafu** - liczba krawędzi w grafie.
**Droga (ścieżka)** - drogą w grafie będziemy nazywać ciąg krawędzi taki, że koniec jednej stanowi początek następnej. Drogę nazywamy **prostą**, gdy **wszystkie jej wierzchołki są różne**.
**Osiągalność** - mówimy, że **v** jest osiągalny z **u**, gdy istnieje droga z **u** do **v**.
**Cykl** - cyklem nazywamy zamkniętą drogę *x<sub>1</sub>x<sub>2</sub>x<sub>3</sub>...x<sub>n</sub>x<sub>1</sub>* w grafie skierowanym, gdzie to wierzchołki *x<sub>1</sub>x<sub>2</sub>...x<sub>n</sub>* to wierzchołki drogi, która jest długości co najmniej 1. **Gdy wszystkie wierzchołki są różne to cykl nazywamy prostym**. **Cykl o długości 1 nazywamy pętlą**.
Mówimy, że ścieżka ***<v<sub>0</sub>, v<sub>1</sub>, ..., v<sub>k</sub>>*** tworzy **cykl** w grafie **nieskierowanym**, gdy **v<sub>0</sub> = v<sub>k</sub>**, **v<sub>1</sub> ... v<sub>k</sub>** są różne oraz **k >=2**
Graf niezawierający cykli nazywamy grafem **acyklicznym**.
Acykliczny graf nieskierowany nazywamy **lasem**.
**Graf prosty** to graf bez krawędzi wielokrotnych i bez pętli.
**Graf regularny** to fraf, w którym wszystkie wierzchołki są tego samego stopnia.
**Graf pusty** to graf, w którym w ogólne nie ma krawędzi (są same wierzchołki izolowane).
**Graf pełny** to graf prosty, w którym każdy wierzchołek jest połączony krawędzią z każdym.
<br/>
**Graf jest spójny**, gdy każda para różnych wierzchołków jest połaczona drogą w tym grafie.
Spójny podgraf grafu **G**, który nie jest zawarty w żadnym większym spójnym podgrafie tego grafu, nazywamy **składową grafu G**.
Spójny, acykliczny graf nieskierowany nazywamy **drzewem (wolnym)**.
**Cykl Eulera** - droga zamknięta przechodząca przez każdą krawędź grafu dokładnie raz.
**Droga Eulera** - droga przechodząca przez każdą krawędź grafu dokładnie raz.
Graf, który posiada cykl Eulera **Musi mieć wszystkie wierzchołki stopnia parzystego**.
Graf, który posiada drogę Eulera ma **albo dokładnie dwa wierzchołki stopnia nieparzystego, albo nie ma w ogóle takich wierzchołków**.
Graf spójny, mający dokładnie 2 wierzchołki stopnia nieparzystego **posiada drogę Eulera**.
<br />
__Formy reprezentacji grafów__
- **Macierz sąsiedztwa**
Macierzą sąsiedztwa grafu (skierowanego lub nie) nazywamy macierz **M** o wymiarze ***VxV***, w której wartości reprezentują wagę połączeń pomiędzy wierzchołkami, 1 gdy połączone, 0 gdy nie ma.

- **Lista sąsiedztwa**
Dane zapisywane są w postaci listy obiektów zawierających wierzchołek grafu, wraz z listą wierzchołków sąsiednich. W przypadku grafu nieskierowanego listy są dłuższe, ponieważ muszą odzwierciedlać krawędzie w obu kierunkach.

- **Macierz incydencji**
Macierz incydencji jest macierzą **A** o wymiarze **n x m**, gdzie **n** oznacza liczbę wierzchołków grafu, natomiast **m** liczbę jego krawędzi. Każdy wiersz tej macierzy odwzorowuje jeden wierzchołek grafu. Każda kolumna odwzorowuje jedną krawędź. Zawartość komurki **A[i, j]** określa powiązanie (incydencję) wierzchołka **v<sub>i</sub>** z krawędzią **e<sub>j</sub>** w sposób następujący:

Jeśli graf jest nieskierowany, to definicję macierzy należy uprościć:

<br/>
__Zastosowania__
**Mapy** - Aby znaleźć najkrótszą drogę by dostać się z jednego miejsca do drugiego można wykorzystać graf, którego wierzchołki będą odpowiadały miejscowością a krawędzie drogom.
**Dokumenty hipertekstowe** - Przeszukując internet napotykamy dokumenty, które zawierają odnośniki do innych dokumentów - internet jest grafem, którego wierzchołkami sa dokumenty a krawędziami odsyłacze.
**Sieci** - Sieć komputerowa zbudowana jest z komputerów, które przesyłają między sobą informacje. Komputery w danej sieci reprezentowane są przez wierzchołki grafu, a połączenia między nimi krawędziami.
**Struktura programu** - Kompilator buduje graf reprezentujący strukturę wywołań podprogramów w kompilowanym programie. Wierzchołkami grafu są różne funkcje, natomiast krawędzie są kojarzone z wywołaniem funkcji./
## 23. Metody projektowania algorytmów (dziel i rządź, programowanie dynamiczne i algorytmy zachłanne).
- **Dziel i rządź**
Polega na rekurencyjnym dzieleniu problemu na mniejsze podproblemy. Dzielenie trwa dopóni nie uzyskamy problemów, które da się w prosty sposób rozwiązać.
Algorytmy wykorzystujące metodę "dziel i rządź":
- Sortowanie przez wybieranie
- Sortowanie przez wstawianie
- Sortowanie przez scalanie
- Quicksort
<br/>
- **Programowanie dynamiczne**
Jest stosowane głównie do rozwiązywania problemów optymalizacyjnych. Jest alternatywą dla niektórych zagadnień rozwiązywanych metodami zachłannymi. Wyniki poszczególnych obliczeń są zapamiętywane w pomocniczej tablicy, która jest wykorzystywana w kolejnych krokach. Eliminuje to konieczność wielokrotnego powtarzania tych samych obliczeń.
Algorytmy wykorzystujące programowanie dynamiczne:
- Algorytm Bellmana-Forda
- Algorytm Helda-Karpa
- Algorytm wykorzystujący problem wydawania reszty
<br/>
- **Algorytm zachłanny**
W każdym kroku dokonuje wyboru będącego na daną chwilę tym najlepszym. Podejmuje decyzje optymalne tylko lokalnie. Kontynuuje działania wynikające z poprzednich decyzji.
Algorytmy wykorzystujące metodę zachłanną:
- Algorytm Dijkstry (poszukiwanie najkrótszych ścierzek)
- Algorytm Kruskala (poszukujący minimalnego drzewa rozpinającego)
## 24. Elementarne i nieelementarne metody sortowania.
Elementarne metody sortowania:
- **Sortowanie przez selekcję (selection sort)** - Jego czas działania jest określany z góry O(n<sup>2</sup>). Sortowanie to jest najlepsze, spośród innych elementarnych do sortowania elementów o małych kluczach i dużych polach, ponieważ wykonuje najmniej wstawień. W pierwszym przebiegu algorytm znajduje najmniejszy element w tablicy i zamienia go z pierwszym. W drugim algorytm znajduje najmniejszy element w podtablicy i zamienia go z drugim. Tak aż do zamiany r-tego elementu z r-1 elementem.
- **Sortowanie bąbelkowe** - Czas działania jest z góry określony przez O(n<sup>2</sup>) - algorytm wykonuje w najgorszym i średnim przypadku podobną ilość porównań i zamian. Zadada działania opiera się na cyklicznym porównywaniu par sąsiadujących elementów i zamianie ich kolejności w przypadku niespełniania kryterium porządkowego zbioru. Operację tę wykonujemy dotąd, aż cały zbiór zostanie posortowany.
<br/>
Nieelementarne metody sortowania:
- **Quicksort (sortowanie szybkie)** - Średnia złożoność obliczeniowa O(*n log n*)Bazuje na strategii dziel i rządź. Problem dzielimy rekurencyjnie na podproblemy a następnie łączymy w jedno rozwiązanie. Z tablicy wybiera się element rozdzielający, po czym tablica jest dzielona na dwa fragmenty: do początkowego przenoszone są wszystkie elementy nie większe od rozdzielającego, do końcowego wszystkie większe. Potem sortuje się osobno początkową i końcową część tablicy. Rekurencję kończy się, gdy kolejny fragment uzyskany z podziału zawiera pojedynczy element, jako że jednoelementowa tablica nie wymaga sortowania.
- **Sortowanie pozycyjne** - Algorytm porządkujący stabilnie ciągi wartości (liczb, słów) względem konkretnych cyfr, znaków itp, kolejno od najmniej znaczących do najbardziej znaczących pozycji. Złożoność obliczeniowa jest równa O(d(n+k)), gdzie k to liczba różnych cyfr, a d liczba cyfr w kluczach. Wymaga O(n+k) dodatkowej pamięci.
## 25. Elementarne metody wyszukiwania. Haszowanie.
**Wyszukiwanie liniowe/sekwencyjne**
- Polega na przeglądaniu kolejnych elementów zbioru **Z**
- W przypadku odnalezienia elementu, który posiada odpowiednie własności, zwraca jego pozycje w zbiorze i kończy pracę.
- W przypadku pesymistycznym, gdy poszukiwanego elementu nie ma w zbiorze lub też znajduje się on na samym końcu zbioru, algorytm musi wykonać przynajmniej **n** obiegów pętli sprawdzającej poszczególne elementy
- klasa złożoności obliczeniowej jest równa **O(n)**
- W przypadku poszukiwania wszystkich wystąpień poszukiwanej własności elementu, algorytm po zwrocie pierwszej odnalezionej pozycji kontunuuje pracę od następnego indeksu.
<br/>
**Wyszukiwanie binarne**
- Opiera się na metodzie **dziel i rządź** oraz działa na uporządkowanych tablicach
- Polega na sprawdzeniu środkowego elementu zbioru oraz przyjęciu nowego podzbioru, gdy środkowy element nie spełnia kryteriów wyszukiwania
- Wyszukiwanie kontynuowane jest w podzbiorze spełniającym warunek porównania **mniejsze-większe**
- W przypadku odnalezienia elementu, posiadającego odpowiednie własności, zwraca on jego pozycję w tablicy i kończy pracę
- Złożoność obliczeniowa równa **O(log<sub>2</sub>n)**
- W przypadku tablicy o milionie elementów, algorytm musi sprawdzić maksymalnie 20 pozycji
<br/>
**Wyszukiwanie max lub min**
- Opiera się na metodzie wyszukiwania liniowego
- Przyjmuje pierwszy element zbioru za tymczasowy maksymalny/minimalny a następnie porównuje go z kolejnym elementem i na podstawie wyniku porównania może przyjąć nowy tymczasowy element maksymalny/minimalny
- Po przejściu przez wszystkie elementy zbioru, wartość elementu tymczasowego zostaje przyjęta jako maksimum lub minimum zbioru
- Złożonośc obliczeniowa równa **O(n)**
<br/>
**Naiwne wyszukiwanie wzorca w tekście**
- Algorytm ustawia okno o długości wzorca **p** na pierwszej pozycji w łańcuchu **s** a następnie sprawdza czy zawartość wzorca **p** i porównywanego fragmentu łańcucha **s** są sobie równe
- W przypadku pozytywnym pozycja okna jest zwracana jako wynik
- Po porównaniu okno przesuwa się o jedną pozycje w prawo i cała procedura powtarza się, dopóki okno nie wyjdzie poza koniec łańcucha **s**
- Posiada złożoność obliczeniową równą **O(n x m)** pesymistycznie, oraz **o(n)** w najlepszym przypadku.
<br/>
**n** - długość łańcucha
<br/>
**m** - długość wzorca
<br/>
**Haszowanie**
- Technika rozwiązywania ogólnego problemu słownika, czyli takiego zorganizowania struktur danych i algorytmów, aby można było w miarę efektywnie przechowywać i wyszukiwać elementy należące do pewnego dużego zbioru danych (uniwersum),
- Przykładem tablicy z haszowaniem jest książka telefoniczna, w której kluczem są imie i nazwisko a wyszukiwaną informacją jest numer telefonu.
- Czas uzyskania informacji jest **niezależny** od rozmiaru tablicy lub położenia elementu
- W najprostszym przypadku wartość **funkcji mieszającej** dla danego **klucza** wyznacza **indeks** szukanej informacji w tablicy (złożoność obliczeniowa wynosi **O(1)**)
- Może wystąpić problem **kolizji**, czyli przypisania przez funkcję mieszającą tej samej wartości dwóm różnym kluczom
**Unikanie kolizji**
- Zastąpienie istniejącego elementu lub rezygnacja ze wstawienia nowego elementu
- **Metoda Łańcuchowa** - przechowywanie elementów o tej samej wartości wewnątrz listy lib drzewa związanych z danym indeksem (pesymistycznie **O(n)**)
- **Adresowanie Otwarte** - nowy element wstawia się w innym miejscu niż wynikałoby to z wartości funkcji mieszającej a nowy indeks określany jest przez dodanie do wartości tzw. funkcji przyrostu **p(i)**, gdzie **i** oznacza numer próby (liczba kolizji)
- **Współczynnik wypełnienia** - iloraz liczby elementów zapisanych w tablicy mieszającej **(m)** od fizycznego rozmiaru tablicy **(n)**, czyli **$a$ = m/n**. Dzięki temu można przewidzieć prawdopodobieństwo wystąpienia kolizji i odpowiednio skorygować fizyczny rozmiar tablicy
- **Haszowanie kukułcze** - stosuje dwie tablice i dwie odpowiadające im funkcje haszujące. Do momentu kolizji elementy wstawiane są do pierwszej tablicy za pomocą pierwszej funkcji haszującej. W wypadku kolizji element wstawiany jest do drugiej tablicy przez drugą funkcję. Jeśli ponownie nastąpi kolizja, to zastępujemy istniejący już obiekt a dla niego zostaje uruchomiona ponowna procedura wstawiania, jednak tym razem na siłę będzie wstawiony do pierwszej tablicy. W przypadku zapętlenia się algorytmu losowane są nowe funkcje haszujące i wszystkie elementy tablucy zostają ponownie przemieszane. Odczyt elementu z tablicy odbywa się zawsze w czasie stałym.
<br/>
**Haszowanie - zastosowania**
- kompilatory, interpretery (w dynamicznych językach obiektowych)
- bazy danych - indeksowanie, łączenie, grupowanie
- analiza i agregacja danych
- trasowanie
- systemy pamięci podręcznej
- monitorowanie
- implementacja zbiorów
- mapowanie
- kompresja danych
- wyszukiwanie wzorca w tekście
<br/>
**Haszowanie - wady**
- Współczesne procesory wykorzystują pamięć podręczną, która przyspiesza odwołania do komórek pamięci operacyjnej, gdy te są zgrupowane blisko siebie. Zastosowanie tablicy mieszającej (z haszowaniem) dla małej liczby elementów może być wolniejsze niż zastosowanie zwykłej tablicy przeszukującej sekwencyjnie
- Występuje ryzyko dużej złożoności obliczeniowej w pesymistycznym przypadku wyszukiwania wynoszącej **O(n)**
- Obliczenie wartości dobrej funkcji haszującej (eliminującej kolizje) może być kosztowne względem czasu lub zasobów pamięci
## 26. Złożoność obliczeniowa algorytmu. Przykłady.
Mierzymy liczbę operacji wykonanych na modelu. Następnie próbujemy znaleźć funkcję, która będzie opisywała liczbę operacji w zależności od wejścia algorytmu. Funkcje te możemy porównać ze sobą.

Ile mamy tu operacji? Przypisanie, pętla for. Jej ciało zawiera jedną operację. Sama pętla wykona się dokładnie tyle razy ule jest elementów tablicy numbers. Liczbę tych elementów określimy jako *n*. Na końcu mamy instrukcję return *sum*.
Dodając do siebie otrzymujemy wzór:
*<center>f(n) = 1+n+1 = n+2</center>*
Zatem złożoność naszego algotyrmu opisana jest przez funkcję *f(n) = n+2*. Tak więc wyznacza się ją poprostu licząc operacje.
Jak oszacować rząd złożoności funkcji?
Wyobraźmy sobie pewien algorytm. Funkcja, która go opisuje to np.: *f(n) = n<sup>3</sup> - 6n<sup>2</sup> + 4n + 12*
Argument n to rozmiar danych wejściowych do algorytmu. Wykres tej funkcji wygląda następująco:

**Notacja Dużego O** zakłada, że istnieje funkcja *g(n)*, dla której spełniona jest poniższa wartość:
$\forall$ n $\geqslant$ n<sub>0</sub> : f(n) $\leqslant$ c $\cdot$ g(n)
Oznacza to, że wynik funkcji *g(n)* pomnożony przez jakąś stałą c, będzie większy bądź równy wynikowi funkcji *f(n)*. Własność ta jest spełniona dla wszystkich *n*, które będą większe od n<sub>0</sub>. Jeszcze łatwiej wygląda to na wykresie:

Pokazuje on dwie funkcje. Pierwszą z poprzedniego wykresu. Druga to wykres funkcji *g(n) = n<sup>3</sup>*. Od pewnego punktu zielona linia jest zawsze ponad czerwoną linią. To nic innego jak oszacowanie z góry. To właśnie robi notacja O. Zatem w naszym przypadku nasza funkcja *f(n)* ma złożoność *O(n<sup>3</sup>)*
## 27. Pojęcie bazy danych - funkcje i możliwości.
Baza danych jest zbiorem danych oraz narzędzi **Zystemu Zarządzania Bazą Danych (SZBD)** przeznaczonego do zarządzania nią oraz gromadzenia, przekształcania i wyszukiwania danych.
To zbiór usystematyzowanych informacji (danych), który dotyczy rzeczywistości a konkretnie określonego jej fragmentu (wycinka), który reprezentuje. Fragment ten określamy mianem obszaru analizy.
**Cechy bazy danych**
- **Trwałośc danych** - oznacza możliwość przechowywania danych w pamięci masowej (trwałej) komputera
- **Niezależność danych** - pozwala osiągnąć większą elastyczność, ponieważ programy wymieniające informacje z bazą danych są niezależne od przechowywania danych na dysku i szczegółów reprezentacji danych na dysku
- **Ochrona danych** - baza danych oferuje mechanizmy kontroli dostępu do danych w sposób umożliwiający użytkowanie danych wyłącznie przez uprawnionych do tego użytkowników
- **Integralność danych** - zgodność z rzeczywistością. Dane w bazie danych są odwzorowaniem rzeczywistości
- **Współdzielenie danych** - poszczególne fragmenty danych mogą być używane przez kilku użytkowników jednocześnie (dostęp współbieżny)
- **Abstrakcja danych** - dane opisują tylko istotne aspekty obiektów świata rzeczywistego
- **Integracja danych** = gwarantująca, że dane i związki między nimi nie powtarzają się jeśli nie jest to konieczne ale wszelkie zmiany w obrębie bazy nie powodują wieloznaczności
<br/>
**System zarządzania bazą danych (SZBD)** obsługuje użytkowników bazy danych, umożliwiając im eklploatację oraz tworzenie baz danych. By stworzyć i zaprojektować bazę danych, nalezy ją zidentyfikować, a do tego konieczne jest określenie typów przechowywanych w niej danych. Istotną rolę odgrywa również wyznaczenie użytkowników oraz ich praw dostępu.
**Właściwości bazy danych (funkcje SZBD)**
- Tworzenie struktur baz danych
- Wykonywanie operacji CRUD (Create, Read, Update, Delete)
- Obsługa zapytań (selekcjonowanie danych)
- Generowanie raportów i zestawień
- Administracja bazą danych
<br/>
**Podział baz danych**
- **Model relacyjno-obiektowy** jest mieszanym modelem bazodanowym, pozwala on w relacyjnych tabelach tworzyć kolumny, w których przechowywane są dane typu obiektowego, pozwala na definiowanie zmiennych oraz metod, które będą wykonywane na danych wprowadzancych do obiektu. Podstawa wielodostępu: identyfikatory użytkowników i ich hasła, procedura logowania system praw dostępu i uprawnień, grupy użytkowników
- **Obiektowy model danych** opiera się na koncepcji obiektów (podobnie jak w
projektowaniu obiektowym – obiekt jest odwzorowaniem rzeczywistości lub abstrakcji).
Odwołania do określonego obiektu w tym modelu bazy danych są wykonywane za
pomocą interfejsu, dzięki któremu są zachowane integralność i bezpieczeństwo danych.
- **Relacyjny model danych** w najprostszym ujęciu w modelu relacyjnym dane grupowane
są w relacje, które reprezentowane są przez tablice. Relacje są pewnym zbiorem
rekordów o identycznej strukturze wewnętrznie powiązanych za pomocą związków
zachodzących pomiędzy danymi. Relacje zgrupowane są w tzw. schematy bazy danych.
Relacją może być tabela zawierająca dane teleadresowe pracowników, zaś schemat
może zawierać wszystkie dane dotyczące firmy. Takie podejście w porównaniu do innych
modeli danych ułatwia wprowadzanie zmian, zmniejsza możliwość pomyłek, ale dzieje się
to kosztem wydajności. W 1985 r. Edgar Frank Codd (twórca) przedstawił 12 zasad
opisujących model relacyjny baz danych.
<br/>
**Postulaty Codda**
- **Postulat informacyjny** – dane są reprezentowane jedynie poprzez wartości atrybutów wierszach tabel.
- **Postulat dostępu** – każda wartość w bazie danych jest dostępna poprzez podanie nazwy tabeli, atrybutu i wartości
klucza podstawowego.
- **Postulat dotyczący wartości NULL** - dostępna jest specjalna wartość NULL dla reprezentacji zarówno wartości
nieokreślonej, jak i nieadekwatnej.
- **Postulat dotyczący katalogu** – wymaga się, aby system obsługiwał wbudowany katalog relacyjny z bieżącym
dostępem dla uprawnionych użytkowników.
- **Postulat języka danych** – system musi dostarczać pełny język przetwarzania danych, który może być używany zarówno
w trybie interaktywnym, jak i w obrębie programów aplikacyjnych, obsługuje operacje definiowania danych, operacje
manipulowania danymi, ograniczenia związane z bezpieczeństwem i integralnością oraz operacje zarządzania
transakcjami.
- **Postulat modyfikowalności perspektyw** – system musi umożliwiać modyfikowanie perspektyw, o ile jest ono semantycznie
realizowalne.
- **Postulat modyfikowalności danych** – system musi umożliwiać operacje modyfikacji danych, musi obsługiwać operatory
INSERT, UPDATE oraz DELETE.
- **Postulat fizycznej niezależności danych** – zmiany fizycznej reprezentacji danych i organizacji dostępu nie wpływają na
aplikacje.
- **Postulat logicznej niezależności danych** – zmiany wartości w tabelach nie wpływają na aplikacje.
- **Postulat niezależności więzów spójności** – więzy spójności są definiowane w bazie i nie zależą od aplikacji.
- **Postulat niezależności dystrybucyjnej** – działanie aplikacji nie zależy od modyfikacji i dystrybucji bazy.
- **Postulat bezpieczeństwa względem operacji niskiego poziomu** — operacje niskiego poziomu nie mogą naruszać modelu relacyjnego i więzów
<br/>
**Elementy relacyjnej bazy danych**
- **Encja** – rodzaj obiektu przechowywanego w bazie. Na przykład towar czy producent. Odpowiednikiem w
programowaniu obiektowym jest klasa.
- **Atrybut** – każda encja ma swoje właściwości. Na przykład pracownik ma numer telefonu, imię czy nazwisko. Każdy z
tych elementów to atrybut. Podobnie jak w programowaniu obiektowym instancję mają swoje atrybuty. Atrybuty
mogą mieć różne typy (np. varchar czyli string).
- **Krotka** – Pojedyncza krotka to wiersz w tabeli. Zbierając kilka wierszy tworzy się relacja. Np. relacja „ubrania” będzie
zawierała wiersze z typami ubrań oraz ich atrybutami.
- **Klucz główny** – zbiór atrybutów (kolumn w tabeli) tworzy klucz główny. Jest to unikalny identyfikator dla każdego wiersza
w tabeli. W większości przypadków tabele zawierają dodatkową kolumnę która zawiera identyfikator. Zazwyczaj jest to
liczba odpowiadająca numerowi wiersza.
- **Klucz obcy** – przez to że tabele mogą być ze sobą powiązane musimy mieć również klucz obcy. Jest to dodatkowa
kolumna (kolumny), która przekazuje zależność. Np. produkty mogą mieć swój klucz główny, a jako klucz obcy będzie
ich producent.
<br/>
KONIEC SLAJD 186!!!
## 28. Relacja i jej atrybuty w bazach danych.
**Rodzaje powiązań w relacyjnej bazie danych**
- **Jeden do jednego** – mając dwie tabele A i B występuje wtedy, gdy każdemu rekordowi z tabeli A jest
przyporządkowany jeden rekord z tabeli B i na odwrót. Np. numer rejestracyjny i samochód.
- **Jeden do wielu** – jest najczęściej używanym typem połączeń. Pomiędzy tabelami A i B występuje wtedy, gdy
pojedynczemu rekordowi z tabeli A jest podporządkowany jeden lub wiele rekordów z tabeli B, natomiast
pojedynczemu rekordowi z tabeli B jest przyporządkowany dokładnie jeden rekord z tabeli A.
- **Wiele do wielu** - pomiędzy tabelami A i B
występuje wtedy, gdy pojedynczemu rekordowi
z tabeli A jest przyporządkowany jeden lub wiele
rekordów z tabeli B i na odwrót. Taka sytuacja
będzie np. w relacji nauczycieli do uczniów.
Każdy nauczyciel ma wielu uczniów i każdego
ucznia uczą różni nauczyciele
**Klucz główny**
Dość często spotykanym problemem na etapie projektowania bazy danych jest określenie, która
kolumna (kolumny) będzie pełnić funkcję klucza głównego. Ponieważ każdy wiersz w tabel musi
my jednoznacznie zidentyfikować , zachodzi potrzeba wybrania atrybutów (kolumn), które
spełniają to zadanie. Klucz główny odgrywa bardzo ważną rolę w tabeli (relacji), dlatego jego
wybór powinien zostać poprzedzony analizą typowanych przez nas kolumn pod kątem
wymienionych poniżej własności:
- **trwałość** – wartość kolumny powinna być stale obecna w wierszu, oznacza to , że kolumna
taka (należąca do klucza głównego) nie może zawierać wartości NULL.
- **unikatowość** – wartość klucza dla każdego wiersza powinna być unikatowa, ponieważ w
niepowtarzalny sposób powinien on identyfikować każdą krotkę (wiersz tabeli). Może się
zdarzyć, że taki niepowtarzalny identyfikator otrzymamy, umieszczając w kluczu głównym
więcej niż jedną kolumnę. Kombinacja wartości, trzech kolumn, które należeć będą do
klucza, będzie unikatowa i jednoznacznie zidentyfikuje każdą krotkę.
- **stabilność** – wartości klucza nie powinny podlegać zmianom. Nie powinno się jako kluczy
głównych używać kolumn przechowujących wartości nietrwałe, np. numer telefonu
komórkowego, ponieważ mimo jego unikatowości każdy człowiek może go zmienić.
Aby jednoznacznie zidentyfikować wiersz tabeli, stosuje się atrybut (kolumnę), której
poszczególne wartości dla kolejnych krotek (wierszy) będą niepowtarzalne
Atrybut będący kluczem głównym możemy stworzyć sztucznie dla przykładu wprowadzając
kolejne numerowanie wierszy 1, 2, 3, 4, 5 itd., pod warunkiem że każdy wiersz ma inny numer.
Możemy również posłużyć się określoną cechą (atrybutem) opisywanej rzeczywistości (encji), np.
dokonując spisu ludności, możemy posłużyć się numerem PESEL. Ponieważ każdy człowiek ma
inny niepowtarzalny numer PESEL, nie zachodzi obawa, że może on się powtórzyć. Taką kolumnę
(atrybut) nazywamy kluczem Głównym (primary key).
<br/>
**Rodzake kluczy**
- **klucz prosty** – to taki, który jest jednoelementowy (składa się z jednej kolumny),
- **klucz złożony** – to taki, który jest kilkuelementowy (składa się z więcej niż jednej
kolumny).
Kluczem może być zatem jedna lub kilka kolumn, które wspólnie będą w stanie jednoznacznie
zidentyfikować pozostałe dane w tabeli (relacji). Kolumny, które należą do kluczy (używa się ich
do jednoznacznej identyfikacji wierszy w tabeli), nazywamy atrybutami podstawowymi.
Kolumny nie należące do kluczy (zawierają dane, które w określonej relacji są przedmiotem opisu)
nazywamy atrybutami opisowymi.
Do łączenia dwóch tabel (np. A i B) za pomocą związków używa się klucza. Klucz pochodzący z
obcej tabeli B (w której jest on kluczem głównym), używany do łączenia tej tabeli z tabelą A,
będzie dla tabeli A kluczem obcym.
**Superklucz** (superkey) – to kolumna lub zestaw kolumn jednoznacznie identyfikujących każda
krotkę tabeli. Super klucz może zawierać kolumny, które samodzielnie mogą nie identyfikować
każdej z krotek. Unikatowa identyfikacja każdej z krotek może odbywać się jedynie przez zestaw
np. dwóch lub trzech atrybutów. Przedmiotem zainteresowań projektantów baz danych jest taki
superklucz, który zawiera minimalny zestaw atrybutów unikatowo identyfikujących krotkę.
**Klucz kandydujący** (nadklucz, klucz potencjalny) o super klucz zawierający minimalną liczbę
kolumn unikatowo identyfikujących krotki relacji. W praktyce to kolumna lub kolumny, których
użycie w charakterze klucza głównego jest rozważane przez projektanta baz danych. To właśnie
twórca bazy danych decyduje, której kolumnie (kolumnom) nada funkcję klucza głównego.
**Klucz główny** (primary key) to klucz, który został wybrany, aby unikatowo identyfikować krotki
tabeli. Klucz główny jest podyktowany wyborem projektanta bazy danych.
h
<br/>
## 29. Spójność referencyjna baz danych.
**Spójność referencyjna** baz danych polega na wprowadzeniu i utrzymaniu powiązań pomiędzy tabelami.
To zespół reguł, które gwarantują logiczną spójność danych wprowadzanych i przechowywanych w bazie.
Zadaniem więzów spójności jest zagwarantowanie tego, aby dane w bazie danych wiernie odzwierciedlały świat
rzeczywisty, dla opisu którego baza danych została zaprojektowana. Więzy spójności definiowane są na etapie
projektowania bazy danych, tworzone wraz z innymi obiektami, przy tworzeniu bazy.
Wyróżniamy dwa typy więzów spójności:
- **Spójność encji** - ograniczają możliwe wartości, jakie mogą się pojawić w wierszu tabeli:
- **Więzy klucza głównego PRIMARY KEY** – wartości w określonych kolumnach jednoznacznie identyfikują wiersz tabeli. W kolumnach klucza głównego nie jest dozwolona pseudo-wartość NULL . Automatycznie jest zakładany indeks na kolumnach tworzących klucz główny. Może być określony tylko jeden klucz główny dla jednej tabeli.
- **Więzy klucza jednoznacznego UNIQUE** – wartości w określonych kolumnach jednoznacznie identyfikują wiersz tabeli. W kolumnach klucza jednoznacznego jest dozwolona pseudo-wartość NULL . Automatycznie jest zakładany indeks na kolumnach tworzących klucz jednoznaczny. Może być określony więcej niż jeden klucz jednoznaczny dla jednej tabeli.
- **Więzy NOT NULL** – w kolumnie nie jest dozwolona pseudo-wartość NULL.
- **Więzy CHECK** – warunek, który ma być prawdziwy dla wszystkich wierszy w tabeli. Nie może zawierać podzapytania ani funkcji zmiennych w czasie, jak Sysdate lub User. Może zawierać nazwy jednej lub więcej kolumn.
- **Spójność referencyjna** - zapewniają, że zbiór wartości w kolumnach klucza obcego jest zawsze podzbiorem zbioru wartości odpowiadającego mu klucza głównego lub jednoznacznego. Ponieważ wartości klucza głównego lub jednoznacznego jednoznacznie określają obiekty, więc klucz obcy wskazuje zawsze na istniejący obiekt. Wartością klucza obcego może też być NULL – wówczas klucz obcy nie wskazuje na żaden obiekt. System zapewnia, aby obiekt wskazywany przez wartość klucza obcego zawsze istniał, niezależnie od wszystkich możliwych operacji na tabelach, w których biorą udział klucze główne, jednoznaczne i obce.
<br/>
## 30. Normalizacja relacji - postaci normalne.
**Normalizacja baz danych** - proces w ramach którego doprowadzamy bazę danych do postaci
normalnych. W przypadku gdy baza danych nie jest znormalizowana występuje redundancja danych.
Redundancja danych w najprostszym wytłumaczeniem jest sytuacją gdy dane się powtarzają np. są zdublowane.
<br/>
**Pierwsza postać normalna** - występuje gdy każda kolumna jest atomowa tzn. nie zawiera list
i dane są niepodzielne.

Przedstawiona tabela nie spełnia pierwszej postaci normalnej (1NF) ponieważ kolumna Adres nie jest atomowa. Możemy ją
podzielić na pojedyncze kolumny. Aby więc doprowadzić naszą tabelę do 1NF należy kolumnę adres podzielić na kilka
pojedynczych kolumn. Poniższa tabela została tak zmieniona, że spełnia 1NF:

<br/>
**Druga postać normalna** - baza danych jest w drugiej postaci normalnej gdy spełnia pierwszą postać normalną oraz wszystkie kolumny w tabeli zależą
tylko od klucza.
Czy powyższa baza jest w 2NF? Nie ponieważ jak się zastanowić to z tabeli możemy wyodrębnić przynajmniej trzy zbiory danych zależne od różnych kluczy: KLIENT, PIZZA, ZAMÓWIENIE.

Powyższa baza została sprowadzona do drugiej postaci normalnej.
<br/>
**Trzecia postać normalna** - Baza jest w trzeciej postaci normalnej wtedy gdy spełnia drugą postać normalną oraz żadna z kolumn nie jest zależna od innej kolumny która nie jest kluczem.
Tabela KLIENT spełnia 3NF natomiast tabela PIZZA jej nie spełnia ponieważ kolumna CENA nie jest zależna od klucza
a od wielkośc i pizzy. Aby to zmienić należy dane dotyczące cen wyciągnąć do inny tabeli jak na poniższym schemacie:

<br/>
**Kolejne postacie normalne**
W bazach danych występują jeszcze inne postaci normalne jak: Byce-Codde, 4NF, 5NF. Kolejne postaci normalne mówią, że naszą bazę można jeszcze bardziej podzielić. Dla przykładu miasto nie jest bezpośrednio związane z adresem a z ulicą na którą zamawiamy dlatego też ulicę można by wyciągnąć do osobnej tabeli.## 31. Modelowanie bazy danych - rodzaje połączeń relacyjnych, pojęcie klucza głównego i obcego.
<a href="<link_to_resource_local_or_)nline_here>"></a><b></b>
**Klucz potencjalny** - minimalny zestaw atrybutów relacji, jednoznacznie identyfikujący każdą krotkę tej relacji. W relacji
może znajdować się wiele kluczy potencjalnych (zwanych czasem **kandydującymi**). Spośród kluczy potencjalnych
wybiera się zazwyczaj jeden klucz, zwany kluczem głównym.
**Klucz główny** (primary key) – wybrany minimalny zestaw atrybutów relacji, jednoznacznie identyfikujący każdy rekord
tej relacji. To oznacza, że taki klucz musi przyjmować **wyłącznie** wartości niepowtarzalne i nie może być wartością
pustą (null). Ponadto każda relacja może mieć najwyżej **jeden** klucz główny.<br>
Kluczem głównym może być dowolny klucz potencjalny, ale często stosuje się rozwiązanie polegające na utworzeniu
specjalnego atrybutu, którego wartości domyślne pobierane są z sekwencji (tzw. autonumeracja), tak aby zapewnić
unikalność klucza.
**Klucz obcy** - kombinacja jednego lub wielu atrybutów tabeli, które wyrażają się w dwóch lub większej liczbie relacji
(tabel). Wykorzystuje się go do tworzenia powiązania pomiędzy parą tabel, gdzie w jednej tabeli ten zbiór atrybutów jest
kluczem obcym, a w drugiej kluczem głównym.
### Związek 1:1 (jeden do jednego)

### Relacja 1:N (jeden do wielu)

### Relacja N:N (wiele do wielu)

## 32. Pojęcie indeksu - rodzaje i zastosowanie.
Indeksowanie jest podstawowym mechanizmem wykorzystywanym w celu optymalizacji baz
danych SQL. Gdyby porównać bazę danych do książki, indeksy są czymś w rodzaju spisu treści.
Z technicznego punktu widzenia (i mocno uogólniając) indeksy to zbiór wartości typu „klucz –
lokalizacja”. Dzięki temu, na podstawie konkretnego klucza czyli parametrów zapytania jest
możliwe bardzo szybkie zwrócenie odpowiednich danych.
Klucze w indeksie przechowywane są w strukturze zwanej B-Tree (nie należy mylić tej
struktury danych z drzewem binarnym). B-Tree pozwala mechanizmom SQL Server znaleźć
pożądany rekord szybciej i wydajniej, ale tylko wtedy, gdy wyszukiwanie w tym drzewie
odbywa się za pomocą klucza.
B-drzewo i Drzewo binarne to typy nieliniowej struktury danych. Chociaż warunki wydają się
być podobne, ale różnią się pod każdym względem.
Drzewo binarne jest używane, gdy rekordy lub dane są przechowywane w pamięci RAM zamiast
na dysku, ponieważ prędkość dostępu do pamięci RAM jest znacznie większa niż na dysku. Z
drugiej strony B-tree jest używane, gdy dane są przechowywane na dysku, skraca czas dostępu,
zmniejszając wysokość drzewa i zwiększając gałęzie w węźle.

Problem z przeszukiwaniem baz danych polega na tym, że tabele nie są posortowane. Jedyna „kolejność” to często klucz
główny PRIMARY_KEY. Nie jest to przydatna kolejność kiedy szukamy danych nie po kluczu a po jakimś innym polu np:
SELECT nazwa_produktu FROM produkty WHERE cena = 128;
W przypadku kiedy dane są posortowane po kluczu głównym trzeba „sprawdzić” wszystkie rekordy i nie mamy
możliwości ułatwienia sobie zadania bo produkty mogą mieć przecież różną cenę. Mówi wtedy że dokonujemy pełnego
skanu tabeli, który działa niekorzystnie na wydajność. Indeksowania polega na unikaniu tego pełnego skanu.
### Jak działają indeksy?
Indeks jest uporządkowanym plikiem rekordów indeksu o stałej długości. Rekordy indeksu zawierają dwa pola: klucz
reprezentujący jedną z wartości występujących w atrybutach indeksowych relacji oraz wskaźnik do bloku danych
zawierający krotkę, której atrybut indeksowy równy jest kluczowi.
### Jak np.MySQL używa indeksów
- szybko znajduje wiersze pasujące do klauzuli
- ignoruje pewne wiersze (jeżeli MySQL ma do dyspozycji wiele indeksów używa tego najmniejszego) co przyspiesza skanowanie,
- szybciej zwraca zapytania w przypadku złączania wielu tabel,
- szybciej zwraca zapytania MIN() i MAX()
### Jakie kolumny i tabele należy indeksować
Korzyść wydajnościowa ze stosowania indeksów jest największa w przypadku dużych tabel (zawierających najwięcej
rekordów) oraz zapytań, które wykonywane są najczęściej.
W MySQL zaleca się indeksować następujące kolumny:
-kolumny najczęściej padające po słowie WHERE,
- kolumny dwóch tabel, które często łączymy,
- kolumny, według których sortujemy dane w raportach (kolumny padające po słowie ORDER BY i GROUP BY),
- kolumny które często zliczamy (SUM(), AVG(), MIN(), MAX(), COUNT())
- klucze obce i kolumny, których będziemy używać tak jak kluczy obcych,
- klucze niepowtarzalne UNIQUE_KEY (typu NIP, PESEL itd...),
### Nadmiar indeksów
Należy pamiętać, że indeks drastycznie **spowalnia dodawanie, modyfikowanie i usuwanie danych**, ponieważ indeksy muszą
być aktualizowane za każdym razem, gdy tabela ulega nawet najmniejszej modyfikacji. Najlepszą praktyką jest dodanie
indeksu dla wartości, które są **często używane do wyszukiwania, ale nie ulegają częstym zmianom.**
### Rodzaje indeksów
- Indeks pogrupowany (clustered)
W jednej tabeli możemy posiadać tylko jeden index klastrowany dla jednej lub wielu kolumn. Założenie takiego indexu
równa się fizycznemu posortowaniu danych na dysku, w związku z tym niemożliwe jest założenie dwóch tego rodzaju
indexów.
Odczyt danych z tabeli która nie jest jest posortowana w przypadku gdy posiada setki tysięcy bądź miliony rekordów jest
bardzo czasochłonne. Serwer bazodanowy musi przejść rekord po rekordzie, by zwrócić dane o które prosimy. W związku z
tym należy założyć index, na przynajmniej jedną kolumnę aby usprawnić proces ‚poszukiwania’ rekordów.
> **CREATE CLUSTERED INDEX** nazwaIndeksu **ON** nazwaTabeli(nazwaKolumny);
Index klastrowany może być tylko jeden, ale może zostać założony na więcej niż jedną kolumnę
> **CREATE CLUSTERED INDEX** IX_EmployeesAgeFullName **ON** Employees(Age,FullName);
Nasza tabela została posortowana najpierw po kolumnie Age a następnie po kolumnie FullName
<br><br>
- Indeks niepogrupowany (non clustered)
Są swego rodzaju kopią danych, kopią kolumny na którą został założony taki index. Możemy posiadać więcej niż jeden index
non-clustred, jednak warto wiedzieć, że podczas zapisu danych do tabeli, jeśli dane wymagają ponownego posortowania, to
operacja zapisu będzię trwać dłużej. Im więcej indexów, tym dłuższy czas oczekiwania na ukończenie operacji. Tego typu
index jest również wolniejszy jeżeli odpytujemy o więcej danych, niż zostało to zadeklarowane na początku.
> **CREATE NONCLUSTERED INDEX** nazwaIndexu **ON** nazwaTablicy(nazwaKolumny);
## 33. Podstawowe konstrukcje języka SQL.
### Cechy języka SQL
- Język wysokiego poziomu
- Jest językiem deklaratywnym, zorientowanym na wynik
- Jest oparty na algebrze relacji
- Zawiera logikę trójwartościową
- Nie posiada instrukcji sterujących wykonywaniem programu
- Nie dopuszcza rekurencji
- Umożliwia definiowanie struktur danych, wyszukiwanie danych oraz operacje na danych
- Działa na zbiorach danych
### Struktura i wykorzystanie języka SQL
- Język SQL jest przykładem języka transformacji, co oznacza, że został on tak zaprojektowany, że
umożliwia przekształcenie relacji wejściowych na relację wyjściową.
- Jest językiem nieproceduralnym, w którym użytkownik opisuje informację, której potrzebuje, ale nie
wskazuje on przy tym, w jaki sposób należy ją odnaleźć.
- Zapytanie języka SQL składa się ze słów zarezerwowanych oraz ze słów zdefiniowanych przez samego
użytkownika. Należy je zapisywać w sposóbdokładny, bez jakichkolwiek zmian, tj. dokładnie tak jak
wymaga tego składnia języka SQL.
- Każde zapytanie w języku SQL jest kończone średnikiem.
### Komponenty języka SQL
- **DDL (Data Definition Language)** – język definiowania struktur danych
(CREATE, DROP, ALTER TABLE).
- **DML (Data Manipulation Language)** – język operacji na danych (SELECT, INSERT, UPDATE, DELETE).
- **Instrukcje sterowania danymi** – kontrola uprawnień użytkowników (GRANT, REVOKE).
### Tabele w języku SQL
Do manipulowania tabelkami używa się kilku poleceń:
- **CREATE TABLE** – definiuje tabelę i jej kolumny,
- **ALTER TABLE** – zmienia tabele i kolumny,
- **DROP TABLE** – usuwa tabelę – jej definicję i zawartość,
- **RENAME** – zmienia nazwę tabeli
Polecenia **CREATE TABLE** i **ALTER TABLE** są ponadto używane w celu definiowania ograniczeń kluczy oraz
tzw. parametrów przechowywania, które są rozszerzeniami składni Oracle.
### Typy danych // Typy tekstowe
- **VARCHAR2(L)** – oznacza typ danych, za pomocą którego można przechowywać ciągi znaków o
zmiennej długości, gdzie L oznacza określoną maksymalną długość zmiennej tego typu. Dopuszczalny
rozmiar dla zmiennej VARCHAR2 wynosi 4000 bajtów.
- **VARCHAR(L)** – pozwala przechowywać napisy o zmiennej długości, których długość może wahać się
od 1 do 2000 znaków.
- **CHAR(L)** – pozwala przechowywać ciągi znaków o stałej długości wskazanej w parametrze rozmiar.
Maksymalna wielkość to 2000 bajtów. Długość domyślna to 1 znak. Ciągi są dopełniane z prawej strony
spacjami do pełnej wielkości pola.
### Typy numeryczne
- **NUMBER(zakres)** – typ całkowity – pozwala przechowywać liczby całkowite ze znakiem mającą tyle
cyfr, ile wynosi parametr zakres (o maksymalnej długości 38 cyfr).
- **NUMBER(zakres, dokładność)** – określa dziesiętną liczbę stałoprzecinkową zapisywaną z dokładnością
do maksymalnie 38 cyfr i wykładnikiem pomiędzy -84 a 127.
- **NUMBER** – określa kolumnę zmiennoprzecinkową z 38 cyframi pamiętanymi dokładnie i wykładnikiem
pomiędzy 125 a -127.
### Typ czasu
- **DATE** – obejmuje okres od pierwszego stycznia 4712 r. p.n.e. do 31 grudnia 4712 r. n.e.
<br> Kolumna typu
DATE może przechowywać czas z dokładnością do sekund.
### Operacje DDL
Tworzenie nowej tabeli
**CREATE TABLE** *nazwa_tabeli (nazwa_kolumny1 typ_danych1)*;
``` CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15),
cena NUMBER(7,2),
kategoria VARCHAR2(30),
stan_magazyn NUMBER,
wycofany CHAR(3) );
CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15),
cena NUMBER(7,2),
kategoria VARCHAR2(30),
stan_magazyn NUMBER,
wycofany CHAR(3) );
Tabele i ich zawartość są usuwane za pomocą polecenia DROP TABLE nazwa_tabeli. Dla tabel, do których nie odwołuje się żaden klucz obcy, tabela i jej zawartość zostanie całkowicie usunięta.
Przykład: DROP TABLE czytelnicy CASCADE CONSTRAINTS;
Przykład: TRUNCATE TABLE towary;
Z pewnymi ograniczeniami, przy użyciu opcji MODIFY polecenia ALTER TABLE można zmienić cztery części definicji kolumny:
Przykład: ALTER TABLE towary MODIFY (kategoria VARCHAR(30) NOT NULL);
Usunięcie kolumny z tabeli:
Przykład: ALTER TABLE nazwa_tabeli DROP COLUMN nazwa_kolumny;
Ograniczenia, jakie można ustawić dla tabel/kolumn służą następującym celom:
Ograniczenia mogą być:
Istnieje kilka możliwości wykorzystania ograniczenia CHECK:
Ograniczenie CHECK jest definiowane:
Przykład:
CREATE TABLE drużyny_pilkarskie (
nr_druzyny NUMBER(4) NOT NULL,
nazwa VARCHAR2(30) NOT NULL,
liczba_goli NUMBER NOT NULL,
liczba_goli_dom NUMBER CHECK(liczba_goli_dom <= liczba_goli), liczba_goli_wyjazd
NUMBER CHECK(liczba_goli_wyjazd <= liczba_goli) );
Nazywanie ograniczeń Jeśli w tabeli wprowadzamy ograniczenia bez podawania ich nazw, wówczas system sam nadaje każdemu ograniczeniu unikalną nazwę, która jest przechowywana w przestrzeni nazw.
Dla przykładu utwórzmy tabelę towary nazywając ograniczenia:
CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15) CONSTRAINT nazwa_nn NOT NULL,
cena NUMBER(7,2) CONSTRAINT cena_nn NOT NULL,
kategoria VARCHAR2(30) CONSTRAINT kategoria_nn NOT NULL, stan_magazyn
NUMBER DEFAULT 0,
wycofany CHAR(3) DEFAULT ‘Nie’,
CONSTRAINT towary_pk PRIMARY KEY(nr_towar),
CONSTRAINT wycofany_CH CHECK(wycofany IN ('Tak', 'Nie')));
W języku SQL poleceniami służącymi do modyfikowania danych w tabelach są jedynie trzy operacje, które zaliczamy do operacji DML:
Za pomocą polecenia INSERT można:
Składnia:
Przykład:
INSERT INTO towary (nr_towar, nazwa, cena, nazwa_kategorii, stan magazynu) VALUES (104, 'chleb', 2.20, 'pieczywo',100);
Składnia DELETE:
DELETE FROM nazwa_tabeli WHERE warunek_logiczny;
Przykład:
DELETE FROM towarywycofane
WHERE nr_towar IN (SELECT nr_towar
FROM towary WHERE stan = 0);
Polecenie TRUNCATE TABLE nazwa_tabeli przyśpiesza proces usuwania dzięki temu, że nie zapisuje informacji sprzed modyfikacji do przestrzeni wycofania. Ten fakt powoduje jednak, iż nie jest możliwe przywrócenie usuniętych danych. To polecenie nie zawiera także klauzuli WHERE, a zatem zawsze usuwa wszystkie wiersze wskazanej tabeli.
Polecenie UPDATE dotyczące aktualizacji danych różni się od pozostałych dwóch operacji DML dotyczących modyfikacji danych w tabelach, ponieważ nie ma wpływu na liczbę wierszy w tabeli.
Składnia:
UPDATE nazwa_tabeli
SET lista
WHERE warunek;
gdzie:
Polecenie UPDATE - przykład
UPDATE towary SET nazwa = ‘czekolada mleczna’, cena = 2.50 WHERE nr_towar = 1;
Podstawową, najczęściej używaną instrukcją języka SQL jest instrukcja SELECT, która służy do pobierania danych z jednej tabeli lub większej liczby tabel (widoków). Niezależnie od liczby tabel i/lub widoków oraz niezależnie od rodzaju operacji wykonywanych na zbiorach lub pseudozbiorach, zawsze jako wynik otrzymujemy wirtualną pojedynczą tabelę (tzw. dynamiczny zestaw wyników), którą dalej możemy przetwarzać.
Składnia:
SELECT lista_kolumn FROM lista_tabel;
Pobranie wszystkich wierszy i wszystkich kolumn:
SELECT * FROM towary;
Pobieranie wszystkich wierszy i wybranych kolumn:
SELECT nazwa, cena FROM towary;
W języku SQL listy przecinkowe są wykorzystywane w różnych celach:
Istotna odmiana listy przecinkowej powstaje w wyniku tzw. aliasingu, czyli nadawania aliasów („pseudonimów”) dla tych elementów, które bezpośrednio poprzedzają alias. Jeśli alias jest umieszczony za określanym elementem, to do tego elementu można odwołać się zarówno poprzez jego nazwę lub alias (poza pewnymi przypadkami, kiedy można odwołać się tylko za pomocą nazwy oraz pewnymi przypadkami, kiedy można odwołać się tylko za pomocą aliasu).
Przykład (nadanie zastępczych aliasów dwóm wyświetlanym kolumnom):
SELECT nazwa nazwa_towaru, cena cena_jednostkowa
FROM towary;
Klauzula ORDER BY instrukcji SELECT służy do sortowania danych w języku SQL. Sortowanie danych można wykonać na dwa sposoby: albo w porządku rosnącym (ustawienie domyślne) – opcja ASC lub w porządku malejącym wartości kolumny użytej do sortowania – opcja DESC.
Przykład:
SELECT nr_towar, nazwa, cena, stan, towary
FROM towary
ORDER BY cena DESC;
Zanim dane z urządzenia źródłowego zostaną przesłane do urządzenia końcowego muszą przejść długą drogę, podczas której najpierw są odpowiednio oznaczane, tagowane, opisywane określonymi informacjami pozwalającymi na ich identyfikację, potem przesyłane są pomiędzy wieloma urządzeniami pośredniczącymi, aż trafią do odbiorcy, który dane to potem musi zinterpretować.
Gdyby nie istniał taki model, który dzieli komunikację na mniejsze, łatwiejsze do zrozumienia i zarządzania etapy oraz określa zadania, jakie muszą być realizowane w poszczególnych warstwach trudno byłoby we właściwy sposób zarządzać komunikacją sieciową ponieważ mnogość rozwiązań i technologii powodowałaby olbrzymi chaos, trudny do opanowania.
Warstwa 7: aplikacji - Udostępnia użytkownikom możliwość korzystania z usług sieciowych, takich jak WWW, poczta elektroniczna, wymiana plików, połączenia terminalowe czy komunikatory.
Warstwa 6: prezentacji - Przekazuje do warstwy aplikacji informacje o zastosowanym formacie danych, np. informuje jakie typy plików będą przesyłane, odpowiada ona również za odpowiednie zakodowanie danych na urządzeniu źródłowym i ich dekodowanie na urządzeniu docelowym.
Warstwa 5: sesji - Warstwa sesji otrzymuje od różnych aplikacji dane, które muszą zostać odpowiednio zsynchronizowane. Synchronizacja występuje między warstwami sesji systemu nadawcy i odbiorcy. Warstwa sesji „wie”, która aplikacja łączy się z którą, dzięki czemu może zapewnić właściwy kierunek przepływu danych –nadzoruje połączenie. Wznawia je po przerwaniu.
Warstwa 4: transportu - Głównym zadaniem jest sprawna obsługa komunikacji pomiędzy urządzeniami. W warstwie tej dane dzielone są na mniejsze części, następnie opatrywane są dodatkowymi informacjami pozwalającymi zarówno przydzielić je do właściwej aplikacji na urządzeniu docelowym, jak i pozwalającymi złożyć je na urządzeniu docelowym w odpowiedniej kolejności.
Warstwa 3: sieci - Warstwa sieciowa jako jedyna dysponuje wiedzą dotyczącą fizycznej topologii sieci. Rozpoznaje, jakie drogi łączą poszczególne komputery (trasowanie) i decyduje, ile informacji należy przesłać jednym z połączeń, a ile innym. Jeżeli danych do przesłania jest zbyt wiele, to warstwa sieciowa po prostu je ignoruje.
Warstwa 2: łącza danych - Głównym zadaniem jest kontrola dostępu do medium transmisyjnego, a także adresowanie danych, tym razem jednak w celu przesyłania ich pomiędzy hostami w sieci LAN.
Warstwa 1: fizyczna - Koduje dane do postaci czystych bitów (zer i jedynek) i przesyła je poprzez medium transmisyjne do odpowiednich urządzeń.


TCP/IP (ang. Transmission Control Protocol/Internet Protocol) to zbiór protokołów służących do transmisji danych przez sieci komputerowe. Model TCP/IP został stworzony w latach 70. XX wieku w DARPA, aby pomóc w tworzeniu odpornych na atak sieci komputerowych. Potem stał się podstawą struktury Internetu. Model TCP/IP implementuje najważniejsze funkcjonalności siedmiu warstw standardowego modelu OSI. Poniższy schemat przedstawia odpowiadające sobie warstwy modeli TCP/IP i OSI.

Każda wiadomość wysłana przez aplikację przechodzi przez wszystkie warstwy TCP/IP, od warstwy aplikacji do najniższej warstwy dostępu do sieci. Następnie jest transmitowana przez sieć do drugiego komputera. Na koniec przechodzi przez wszystkie warstwy w przeciwnym kierunku, aż do warstwy aplikacji i docelowego procesu. Podczas przesyłania danych z aplikacji do sieci, każda warstwa dodaje swój własny nagłówek do każdej wiadomości. Każdy z tych nagłówków jest potem odczytywany przez odpowiednią warstwę w komputerze odbierającym wiadomość. Zarówno zawartość jak i wielkość nagłówków zależą od użytych protokołów.


Pośredniczy w komunikacji pomiędzy programami komputerowymi i protokołami niższych warstw, umożliwiając w ten sposób aplikacjom korzystanie z sieci. Jest to warstwa najbliższa użytkownikowi, ponieważ to właśnie ona pozwala nam w pełni korzystać z usług sieciowych. Kiedy siadamy przed komputerem i uruchamiamy np. przeglądarkę internetową to korzystamy z sieci właśnie na poziomie warstwy aplikacji. Istnieje wiele protokołów warstwy aplikacji, które wykorzystują transmisję TCP/IP.
Budowa wiadomości warstwy aplikacji różni się w zależności od protokołu, który został użyty. Każdy protokół może wymagać różnych danych wejściowych i produkować różne zapytania, które będą wysłane do warstwy transportowej. Niezależnie od formy wiadomości utworzonej przez warstwę aplikacji, warstwa transportowa traktuje każdą otrzymaną wiadomość jako dane i nie wnika w ich zawartość.
Gniazda sieciowe to struktury, które są wykorzystywane podczas komunikacji pomiędzy warstwami aplikacji i transportową. Każdy proces i aplikacja, który próbuje połączyć się z siecią, musi powiązać swoje kanały transmisji danych wejściowych i wyjściowych poprzez utworzenie właściwego obiektu gniazda sieciowego.
Obiekt gniazda sieciowego zawiera informacje o adresie IP, numerze portu i użytym protokole warstwy transportowej. Unikalna kombinacja tych trzech parametrów pozwala na zidentyfikowanie właściwego procesu, do którego wiadomość powinna być dostarczona.
Numer portu może zostać przypisany automatycznie przez system operacyjny, ręcznie przez użytkownika lub może być mu przypisana wartość domyślna, właściwa pewnym popularnym aplikacjom. Numer portu jest 16-bitową liczbą całkowitą (0 - 65535).
Niektóre popularne protokoły warstwy aplikacji używają domyślnych i publicznie znanych numerów porów. Na przykład, HTTP używa portu 80, HTTPS używa portu 443, SMTP portu 25, Telnet portu 23, natomiast FTP używa dwóch portów: 20 do transmisji danych i 21 kontroli transmisji. Lista domyślnych numerów portów jest zarządzana przez organizację Internet Assigned Numbers Authority.
Jej głównym zadaniem jest sprawna obsługa komunikacji pomiędzy urządzeniami. W warstwie tej dane dzielone są na mniejsze części, następnie opatrywane są dodatkowymi informacjami (nagłówki) pozwalającymi zarówno przydzielić je do właściwej aplikacji na urządzeniu docelowym, jak i pozwalającymi złożyć je na urządzeniu docelowym w odpowiedniej kolejności. Nagłówek zawiera szereg informacji kontrolnych, w szczególności numery portów nadawcy i odbiorcy.
Najpopularniejszym protokołem warstwy transportowej jest TCP (ang. Transmission Control Protocol). Podczas transmisji danych, TCP zestawia połączenie pomiędzy komunikującymi się stronami przez zainicjowanie tzw. sesji (ang. session). TCP jest protokołem niezawodnym, w którym odbiorca potwierdza otrzymanie każdej wiadomości. Wszystkie wiadomości dostarczane są w takiej samej kolejności, w jakiej zostały wysłane. Wszystkie cechy wymienione powyżej są zapewniane przez warstwę TCP. Oznacza to, że TCP może współdziałać z innymi, bardziej zawodnymi protokołami niższych warstw i nie powinno to afektować komunikacji z perspektywy warstwy aplikacji.
Odbiorca testuje każdy otrzymany pakiet pod kątem błędów transmisji (poprzez wyliczanie sumy kontrolnej danych). Jeśli wiadomość jest poprawna, odbiorca wysyła potwierdzenie do nadawcy. Jeśli nadawca nie otrzyma potwierdzenia w przeciągu określonego (konfigurowalnego) czasu, to ponownie wysyła zagubiony pakiet. Po kilku nieudanych próbach, TCP zakłada, że odbiorca jest nieosiągalny i informuje warstwę aplikacji, że transmisja zakończyła się niepowodzeniem.
Jedno z pól nagłówka TCP zawiera numer sekwencyjny wiadomości. Numer sekwencyjny jest zwiększany o jeden dla każdej wysłanej wiadomości. Podczas odbierania wiadomości, TCP układa pakiety we właściwej kolejności. Dzięki temu, warstwa aplikacji nie musi w ogóle zajmować się kolejnością przychodzących pakietów sieciowych.
Składa się z 20 lub więcej bajtów. Dokładna wielkość zależy od tego czy opcjonalne pole opcji jest używane. Maksymalna wielkość tego pola to 40 bajtów, więc maksymalna wielkość całego nagłówka to 60 bajtów.

W celu wymiany danych przy pomocy TCP, dwie aplikacje muszą najpierw
zainicjować sesję.
TCP wymaga wymiany trzech wiadomości żeby utworzyć sesję:
Kiedy transmisja pomiędzy klientem i serwerem zostanie zakończona, sesja powinna zostać zamknięta. Każda strona komunikacji może zakończyć trwającą sesję. Druga strona powinna odpowiedzieć na to, wysyłając odpowiednie potwierdzenie.
Zastosowanie TCP. TCP jest szeroko wykorzystywane w protokołach i aplikacjach, które wymagają wysokiej niezawodności. Można wymienić wiele protokołów warstwy aplikacji, które używane są głównie razem z TCP.
Jednymi z najpopularniejszych są:
Drugim popularnym protokołem używanym w warstwie transportowej jest UDP (ang. User Datagram Protocol lub Universal Datagram Protocol). Jest to prostszy protokół, w którym komunikacja odbywa się bez nawiązywania żadnego stałego połączenia pomiędzy aplikacjami. Wszystkie pakiety wysyłane są niezależnie od siebie. Dzięki swojej prostocie UDP jest szybsze niż TCP. Z drugiej jednak strony, nie zapewnia takiej niezawodności działania jak TCP, nie gwarantuje, że wiadomości rzeczywiście dotarły do odbiorcy. UDP nie dostarcza pakietów w takiej samej kolejności, w jakiej zostały one wysłane. Ciężar uporządkowania otrzymywanych wiadomości i sprawdzenia czy nie nastąpiły błędy transmisji spoczywa na otrzymującej je aplikacji.
Składa się z 8 bajtów, jest więc znacznie krótszy niż odpowiadający mu nagłówek TCP.

UDP jest preferowane jeśli przesyłane pakiety danych są nieistotne lub komunikacja musi odbywać się z wyjątkowo dużą prędkością czyli np. podczas transmisji audio i video, gdzie utrata pewnej liczby pakietów nie jest bardzo uciążliwa dla odbiorcy. Istnieje wiele protokołów warstwy aplikacji, które używają UDP, na przykład:
Datagram Congestion Control Protocol jest protokołem, który umożliwia aplikacjom
kontrolowanie przepływu danych w celu zapobiegania przeciążeniom sieci i utrzymywania
stabilnych połączeń. DCCP nie zapewnia niezawodnej komunikacji z zachowaniem kolejności
wysyłanych pakietów.
DCCP jest wykorzystywany przez aplikacje, które operują na szybko zmieniających się
danych (dane audio i video, gry online, VoIP). W takich sytuacjach często preferuje się użycie
nowej porcji dostępnych danych, zamiast proszenia o retransmitowanie starego
uszkodzonego pakietu.
Resource Reservation Protocol umożliwia zdalne rezerwowanie zasobów przy użyciu sieci
komputerowych. Jest używany głównie przez routery i serwery w celu zapewnienia usług
o określonej jakości dla klientów.
RSVP jest w stanie rezerwować pasma transmisji dla komunikacji pomiędzy dwoma
komputerami oraz pomiędzy jednym serwerem i wieloma klientami. Wymiana wiadomości w
ramach RSVP jest inicjowana przez klienta (odbiorcę), który prosi router (serwer)
o zarezerwowanie zasobów.
Stream Control Transmission Protocol umożliwia przesyłanie wielu strumieni danych
spakowanych razem w pojedynczym strumieniu. Podobnie jak TCP, SCTP zapewnia
niezawodną transmisję z zachowaniem kolejności pakietów i zapobieganiem przeciążeniom,
dodatkowo rozbudowując jego funkcjonalności o umieszczanie pokrewnych strumieni danych
w tych samych wiadomościach.
Ogólnie rzecz biorąc SCTP, jest bardzo rozbudowanym protokołem zapewniającym
dobrą jakość komunikacji. Niestety, z racji braku wspierania tego protokołu przez
najpopularniejsze routery i systemy operacyjne, nie jest on popularny i szerzej używany.
Głównym zadaniem jest odnalezienie najkrótszej i najszybszej drogi do urządzenia docelowego przez sieć rozległą, podobnie jak robią to samochodowe GPS’y, ale także adresowanie danych z wykorzystaniem adresów logicznych (adresów IP). Adres IP jest unikalnym wirtualnym numerem, który umożliwia znajdowanie urządzenia w sieci. Istnieje kilka popularnych protokołów, które działają w warstwie internetowej. Najpopularniejszym i najważniejszym z nich jest IP (Internet Protocol), ale warto wymienić też
Inne protokoły warstwy internetowej:
IP służy do przesyłania pakietów danych przez sieć. Obecnie używane są dwie wersje tego protokołu, IPv4 i IPv6.
IP nie zapewnia żadnego systemu potwierdzania dostarczenia wiadomości, co oznacza, że nie jest niezawodnym protokołem. Obowiązek upewniania się, że wszystkie dane zostały dostarczone spoczywa na protokole TCP operującym w warstwie transportowej. Całe połączenie TCP/IP jest więc niezawodne.
Pakiety danych otrzymywane z warstwy transportowej są dzielone na mniejsze datagramy.
Każdy datagram zawiera nagłówek IP oraz bajty otrzymane z warstwy transportowej.
Maksymalna wielkość datagramu zależy od wersji IP: 216−1 bajtów dla IPv4 oraz 232−1
dla IPv6. Jeśli pakiet otrzymany z warstwy transportowej jest zbyt duży, zostanie podzielony
na kilka datagramów o odpowiedniej wielkości.
Zwykle dane dzielone są na mniejsze datagramy niż wynikałoby to z ograniczeń protokołu IP.
Jest to spowodowane ograniczonymi możliwościami fizycznymi sieci komputerowych. Na
przykład, maksymalna wielkość ethernetowych pakietów wynosi 1 500 bajtów, więc zwykle
datagramy tworzone w warstwie internetowej operującej na ethernecie będą nieco mniejsze
niż 1 500 bajtów (aby umożliwić niższym warstwom dodanie swoich nagłówków).
Maksymalna wielkość datagramu w sieci jest nazywana MTU (Maximum Transfer Unit).
IP umożliwia dzielenie datagramów na mniejsze datagramy, jeśli przechodzą one przez sieć z
mniejszą wartością MTU. Kiedy mniejsze datagramy docierają znowu do sieci o większej
wartości MTU, mogą zostać ponownie zebrane do większego pakietu. W nagłówku IP jest
specjalne pole pozwalające na przeprowadzanie takich operacji (nazywające się Fragment Offset).
Umożliwia przesłanie datagramów z warstwy internetowej, przez fizyczną sieć do drugiego
komputera, gdzie są one przesyłane przez odpowiadającą jej warstwę dostępu do sieci do
warstwy internetowej, a następnie poprzez pozostałe warstwy do docelowej aplikacji.
Obecnie, większość komputerów jest podłączona do sieci ethernetowych, które mogą być
zarówno przewodowe jak i bezprzewodowe. Wobec tego protokoły TCP/IP wyższych warstw
najczęściej są używane razem z zestawem protokołów ethernetowych.
Istnieją trzy warstwy ethernetowe. Pierwsze dwie, Logic Link Control (LLC) i Media Access Control (MAC), odpowiadają warstwie łącza danych w modelu OSI. Trzecia, najniższa warstwa to warstwa fizyczna, podobnie jak w modelu OSI.

Jej najważniejszym zadaniem jest przekazanie informacji do docelowej maszyny odnośnie tego jaki protokół powinien być użyty w warstwie transportowej. Umożliwia to poprawne odczytanie przychodzącej wiadomości przez odbiorcę. Warstwa LLC dopisuje informacje o protokole użytym w warstwie internetowej i o protokole, który powinien otrzymać wiadomość. Pozwala to warstwie LLC na docelowym komputerze poprawnie dostarczyć otrzymane datagramy. Zdefiniowana przez standard IEEE 802.2.
jest odpowiedzialna za tworzenie końcowej wiadomości ethernetowej, która będzie wysłana przez sieć komputerową. Podobnie jak inne warstwy, warstwa MAC tworzy swój własny nagłówek i dodaje go do wiadomości. Nagłówek zawiera adresy MAC nadawcy i odbiorcy, czyli fizyczne adresy dwóch komunikujących się maszyn. Jeśli docelowa maszyna znajduje się za routerem, w innej sieci, to pole adresu odbiorcy będzie miało wartość adresu
routera. Adres MAC odbiorcy będzie zmieniony na inny przez router, kiedy będzie on przetwarzał wiadomość. Warstwa MAC dodaje również 4 kontrolne bajty CRC, które mogą być wykorzystane do naprawienia uszkodzonej wiadomości. Warstwa MAC dla sieci przewodowych jest zdefiniowana przez standard IEEE 802.3. Sieci bezprzewodowe są zdefiniowane przez IEEE 802.11. Warstwa Fizyczna Warstwa fizyczna jest odpowiedzialna za przekształcanie wiadomości w (zależności od typu sieci) impulsy elektryczne lub fale elektromagnetyczne oraz za transmitowanie ich przez sieć fizyczna pomiędzy komunikującymi się maszynami. Jest zdefiniowana przez te same specyfikacje co warstwa MAC, IEEE 802.3 i IEEE 802.11.
![]()
Cechy:
Cechy:
![]()
Cechy:
Cykl życia oprogramowania - Okres czasu rozpoczynający się kiedy pojawił się pomysł na oprogramowanie
Testowanie Oprogramowania - Jest to proces związany z wytwarzaniem oprogramowania. Jest on jednym z procesów kontroli jakości oprogramowania.
Podstawowym standardem dla testowania oprogramowania jest IEEE 829-1998 (829 Standard for Software Test Documentation).
Rodzaje testów:
Testy Manualne Testy wykonywane ręcznie przez testera, który przechodzi przez interfejs użytkownika zgodnie z określoną sekwencją kroków:
Testy dopasowane do aktualnego zapotrzebowania/przeznaczenia
Testy automatyczne Testy automatyczne skutecznie przyspieszają proces tworzenia testów systemowych, ich wykonywanie oraz analize, a tym samym pozwalają na wcześniejsze wykrycie i weliminowanie błędów w aplikacjach.
UML - Unified Modeling Language jest to język modelowy używany między innymi w inżynierii oprogramowania jako standardowy sposób wizualizacji projektu systemu.
Do kreacji UML przyczyniła się potrzeba standaryzacji różnych systemów wizualizacji systemów
rozwiazywania problemów. Został zaproponowany przez Rational software w połowie lat 90-
tych.
W 1997 UML został zaimplementowany przez Object Management Group jako główny system
organizacji, co było punktem przełomowym w popularyzacji języka.
W 2005 UML zostało zaadoptowane do standardu ISO (International Operation of
Standardization) i od tamtego czasu przechodzi okresowe rewizje, w 2020 roku wprowadzono
specyfikacje wersji 2.5.1
UML to sposób wizualizacji architektury systemów za pomocą diagramu. UML składa się ze standardowych elementów, które mają na celu przyspieszenie pracy. Diagram posiada sposoby wizualizacji miedzy innymi:
UML nie narzuca żadnego systemu pracy, ani żadnego systemu projektowania
oprogramowania. Jest jednak narzędziem, która wspomaga projektowanie tych systemów.
W programowaniu, bardzo dobrze sprawdza się jako sposób wizualizacji jak ma działać
program opierający się na obiektach.
Są różne systemy i UML stara się zaproponować wizualizacje każdego z nich za pomocą
różnych elementów, wyspecjalizowanych lub nie. Idea natomiast jest taka sama.
Diagram składa się z zawsze z wizualizacji danego obiektu, oraz interakcji między nimi.
Z takich standardowych przykładów używania UML możemy wymienić reprezentację systemu
za pomocą bramek logicznych.
UML 2 posiada wiele typów diagramów, które można podzielić na 2 typy :


Zespół projektowy jest to jednostka organizacyjna, powołana na zasadzie specjalizacji przedmiotowej, realizująca projekt pod bezpośrednim nadzorem kierownika projektu.
Grupa metod wytwarzania oprogramowania opartego na programowaniu iteracyjno-przyrostowym. Najważniejszym założeniem metodyk zwinnych jest obserwacja, że wymagania odbiorcy (klienta) często ewoluują podczas trwania projektu. Pojęcie zwinnego programowania zostało zaproponowane w 2001 w Manifeście Programowania Zwinnego.
„(...) Bardziej cenimy:
Ludzi i interakcje od procesów i narzędzi Działające
oprogramowanie od szczegółowej
dokumentacji
Współpracę z klientem od negocjacji umów
Reagowanie na zmiany od realizacji założonego planu.
Oznacza to, że elementy wypisane po prawej są wartościowe, ale większą wartość mają dla nas te, które wypisano po lewej.”
Są to iteracyjne i przyrostowe ramy postępowania zgodne ze Scrum Guide. Zgodnie z definicją ze Scrum Guide’a w obręb Scruma wchodzą: Zespoły Scrumowe oraz związane z nimi role, wydarzenia, artefakty i reguły.
ROLE: DEWELOPERZY + PRODUCT OWNER + SCRUM MASTER = ZESPÓŁ SCRUMOWY Deweloperzy, czyli zespół składający się z 3 9 osób z np.testera, analityka, webdewelopera, programisty dowolnego języka. Odpowiadają za sposób wykonania zadań. W zespole wszyscy powinni być równi. Product Owner odpowiada za wybór zadań do wykonania. Product Owner to osoba reprezentująca klienta , ciało jednoosobowe, jedyne, które może zlecać zadania zespołowi, dlatego bardzo ważne jest wsparcie jego roli w organizacji. Scrum Master czuwa nad tym, aby przebieg prac był zgodny z zasadami Scruma i ustalonymi przez zespół. Osoba ta odpowiedzialna jest za usuwanie wszelkich przeszkód uniemożliwiających zespołowi wykonanie zadania.
WYDARZENIA:
PLANOWANIE SPRINTU
CODZIENNY SCRUM +
PRZEGLĄD SPRINTU +
RETROSPEKTYWA =
SPRINT
ARTEFAKTY: BACKLOG PRODUKTU + BACKLOG SPRINTU + PRZYROST
Backlog Produktu to uporządkowana lista wszystkich rodzajów zadań potrzebnych do rozwoju, utrzymania i naprawy produktu.
Lista ta jest otwarta dla wszystkich w organizacji, natomiast Product Owner ma ostateczne słowo co do treści, wyglądu i
zawartości Backlogu. To jest jego narzędzie pracy nad produktem.
Backlog Sprintu to analogiczne narzędzie, ale dla Zespołu Deweloperskiego, który dzięki temu artefaktowi w pełni panuje nad
pracami zaplanowanymi na Sprint.
Przyrost to ukończona przez Zespół zgodnie z Definicją Ukończenia praca na koniec każdego i wszystkich razem Sprintów.
REGUŁY: PRZEJRZYSTOŚĆ + INSPEKCJA + ADAPTACJA
Przejrzystość zapewnia Zespowi Scrumowemu i wszystkim w organizacji dostęp do całości prac i takie samo rozumienie
każdego elementu Scruma. Dzięki temu nie ma niejasności i nieporozumień.
Inspekcja pozwala na bieżące monitorowanie i weryfikowanie przedmiotu pracy i sposobu pracy Zespołu.
Adaptacja powinna być wynikiem Inspekcji i prowadzić do niezbędnych zmian naprowadzających Zespół na właściwy tor
pracy.## 41. Pojęcie Maszyny Turinga - idea pracy automatu, hipoteza Churcha-Turinga
Maszyna Turinga - stworzona przez Alana Turinga prosta maszyna logiczna (licząca) służąca do wykonywania algorytmów. Wszystkie współczesne komputery dają się do niej sprowadzić. Problem jest rozwiązalny na komputerze, jeśli da się zdefiniować rozwiązującą go maszynę Turinga.
Maszyna Turinga zbudowana jest z trzech głównych elementów:
Taśma
Nieskończona taśma jest odpowiednikiem współczesnej pamięci komputera. Taśma dzieli się na komórki, w których umieszczone zostały znaki przetwarzane przez maszynę Turinga. Symbole te stanowią odpowiednik danych wejściowych. Maszyna Turinga odczytuje te dane z kolejnych komórek i przetwarza na inne symbole, czyli dane wyjściowe. Wyniki obliczeń również są zapisywane w komórkach taśmy.

Można definiować różne symbole dla maszyny Turinga. Najczęściej rozważa się jedynie symbole 0, 1 oraz tzw. znak pusty - czyli zawartość komórki, która nie zawiera żadnej danej do przetworzenia. Wbrew pozorom taki prymitywny zbiór trzech symboli jest równoważny logicznie dowolnemu innemu zbiorowi
Głowica
Aby przetwarzać dane, maszyna Turinga musi je odczytywać i zapisywać na taśmę. Do tego celu przeznaczona jest właśnie głowica zapisująco-odczytująca, która odpowiada funkcjonalnie urządzeniom wejścia/wyjścia współczesnych komputerów lub układom odczytu i zapisu pamięci.
Głowica zawsze znajduje się nad jedną z komórek taśmy. Może ona odczytywać zawartość tej komórki oraz zapisywać do niej inny symbol - na tej zasadzie odbywa się przetwarzanie danych - z jednych symboli otrzymujemy inne. Oprócz odczytywania i zapisywania symboli w komórkach głowica wykonuje ruchy w prawo i w lewo do sąsiednich komórek na taśmie. W ten sposób może się ona przemieścić do dowolnie wybranej komórki taśmy.
Przed rozpoczęciem pracy maszyny Turinga głowica jest zawsze ustawiana nad komórką taśmy zawierającą pierwszy symbol do przetworzenia. W klatce taśmy po lewo jest zapisany specjalny znak, tzw. lewy ogranicznik. Jeżeli głowica znajduje się nad lewym ogranicznikiem, to nie może go zamazać ani przesunąć się na lewo od niego. Po zakończeniu danych wejściowych taśma wypełniona jest w nieskończoność specjalnymi pustymi symbolami, tzw. blank'ami.
Układ Starowania
Przetwarzaniem informacji zarządza układ sterowania głowicą. Jego współczesnym odpowiednikiem jest procesor komputera. Układ ten odczytuje za pomocą głowicy symbole z komórek taśmy oraz przesyła do głowicy symbole do zapisu w komórkach. Dodatkowo nakazuje on głowicy przemieścić się do sąsiedniej komórki w lewo lub w prawo.
Podstawą działania maszyny Turinga są stany układu sterowania. Stan układu sterowania określa jednoznacznie jaką operację wykona, jak zareaguje maszyna Turinga, gdy odczyta z taśmy określony symbol.
Zatem operacje wykonywane przez układ sterowania zależą od dwóch czynników:
Stany będziemy określać kolejnymi nazwami: q0, q1, q2, ... ,qn, gdzie q0 jest stanem początkowym, w którym znajduje się maszyna Turinga przed rozpoczęciem przetwarzania symboli na taśmie.
Instrukcją dla maszyny Turinga jest następująca piątka symboli:

S0 i qi są tzw. częścią identyfikacyjną instrukcji. Maszyna Turinga wykonuje tyle różnych instrukcji, ile zdefiniujemy części identyfikacyjnych - w programie nie może być dwóch różnych instrukcji o identycznej części identyfikacyjnej.
Sz, qj i L/P są tzw. częścią operacyjną, która określa jakie działanie podejmuje dana instrukcja. Części operacyjne różnych instrukcji mogą być takie same - oznacza to jedynie, iż instrukcje te wykonują dokładnie to samo działanie.
Przyklad instrukcji
Jeżeli odczytanym przez głowicę symbolem z taśmy będzie symbol A, a układ sterowania znajduje się w stanie q0, to głowica zamieni ten symbol na B, stan wewnętrzny nie zmieni się (pozostanie dalej q0), a głowica przesunie się do sąsiedniej komórki po prawej stronie.
Formalna Definicja
Każdy problem, który może być intuicyjnie uznany za obliczalny, jest rozwiązywalny przez maszynę Turinga.
Sformułowanie "intuicyjnie uznany za obliczalny" uniemożliwia przeprowadzenie matematycznego dowodu tej hipotezy.
Bardziej praktyczna definicja
Każdy problem, dla którego przy nieograniczonej pamięci oraz zasobach istnieje efektywny algorytm jego rozwiązywania, da się rozwiązać na maszynie Turinga
Trzecie równoważne sformułowanie
Każdy nieinteraktywny program może być zredukowany do rozwiązującej go maszyny Turinga, a ta może być wyrażona w każdym zupełnym w sensie Turinga języku programowania.
Dlatego równoważne sformułowanie tej hipotezy mówi, że każdy istniejący algorytm można wyrazić w każdym zupełnym języku programowania.
Translacja Adresów Sieciowych (Network Adress Translation, NAT) - technika przesyłania ruchu sieciowego poprzez router, która wiąże się ze zmianą źródłowych lub docelowych adresów IP, zwykle również numerów portów TCP/UDP pakietów IP podczas ich przepływu. Zmieniane są także sumy kontrolne (zarówno w pakiecie IP, jak i w segmencie TCP/UDP), aby potwierdzić wprowadzone zmiany.
Alternatywna Definicja
NAT jest procesem modyfikującym informację o adresie IP w nagłówku pakietu IP, w momencie przesyłania ruchu przez urządzenie sieciowe. W większości konfiguracji, NAT podmienia prywatne adresy wewnątrz sieci na adresy IP publiczne, udostępniane przez dostawcę usługi dostępu do internetu. Taki zabieg pozwala komputerom w sieci domowej czy firmowej współdzielić połączenie internetowe. Dodatkowo, uzyskuje się zwiększony poziom bezpieczeństwa sieci, ponieważ dostęp do sieci wewnętrznej z zewnątrz jest mocno ograniczony.
Dwa podstawowe typy NAT:
Wyróżniamy trzy rodzaje SNAT:
W momencie, gdy wraca do nas odpowiedź na ten pakiet urządzenie NAT przypisuje pakietowi odpowiedni adres lokalnego węzła. Odwzorowania między pakietami a adresami zapamietywane są w tablicy translacji NAT.
Przyklady działania SNAT`U
Wysyłanie request`u przez (Statyczny/Dynamiczny SNAT):

Otrzymanie odpowiedzi przy (Statycznym/Dynamicznym SNAT):

Otrzymanie odpowiedzi z wlączanym PAT:

Trasowanie (Routing) - to mechanizm wyznaczania trasy i przesyłania pakietów danych w intersieci, od stacji nadawczej do stacji odbiorczej.
Intersieć - to minimum dwie sieci fizyczne połączone ze sobą za pomocą routera.
Trasowaniem zajmuje się urządzenie zwane routerem: może to być zwykły komputer jak i urządzenie specjalnie dedykowane tylko do tego zadania, tzw. router sprzętowy.
Trasowanie umożliwia danym z jednej sieci lokalnej dotrzeć do innej sieci lokalnej, która może znajdować się w dowolnym miejscu na świecie. Trasa może prowadzić przez wiele sieci pośrednich, tak więc routing jest jakby spoiwem łączącym Internet w całość. Bez routowania cały ruch danych byłby ograniczony do jednej fizycznej sieci.
UWAGA
Trasowanie realizowane jest w warstwie trzeciej (sieciowej) modelu OSI. Wyznaczane trasy pakietów danych musza być jak najbardziej optymalne – czyli możliwie najszybsze, ale umożliwiające dostarczenie wszystkich pakietów.
Pakiet to jednostka informacji, której źródłem i przeznaczeniem jest warstwa Sieciowa (warstwa 3) modelu OSI. Pakiet składa się z trzech elementów:
Nagłówek i końcówka zawierają informację sterującą przeznaczoną dla warstwy 3 w stacji odbiorczej. Można powiedzieć, że dane z wyższej warstwy są otoczone (kapsułkowane) przez nagłówek i końcówkę warstwy 3.
Datagram jest jednostką informacji, której źródłem i przeznaczeniem jest warstwa Sieciowa (warstwa 3) modelu OSI, używająca bezpołączeniowej obsługi sieci. Pakiet (połączeniowa obsługa sieci) = datagram (bezpołączeniowa)
Etapy trasowania:
Tablica Routingu
Router przechowuje tzw. tablicę routingu, dzięki której wie, jak kierować ruchem. Najważniejsze informacje zawarte w tablicy to adresy sąsiednich routerów i adresy sieci docelowych.
| Aby dotrzeć do sieci | Wyślij do urządzenia o adresie |
|---|---|
| 10.1.1.0 | 10.1.2.2 |
| 10.1.2.0 | 10.1.2.2 |
| 10.1.3.0 | Bezpośrednio połączony |
Oprócz tego w tablicy mogą się też znaleźć informacje o całościowym koszcie (metryce) wysłania daną trasą pakietu (jest to pewna liczba przypisana trasie przez protokoły routingu), nazwy czy adresy interfejsów sieciowych, przez które dany pakiet jest kierowany do sieci, flagi opisujące właściwości danej ścieżki (H - ścieżka do konkretnego komputera, a nie np. do kolejnego routera, U – ścieżka jest drożna i działa bez problemów), licznik określający czas, jaki upłynął od ostatniego uaktualnienia informacji o trasie.
Pakiet danych przechodzi pomiędzy kolejnymi sieciami. Takie kolejne przejście nazywane jest przeskokiem lub hop-em. Tablica routingu zawarta w routerze lub w komputerze sieciowym zawiera właśnie przyporządkowania adresów dotyczące jednego hopu!

Pod względem sposobu wypełniania danymi tych tablic, dzielimy routing na statyczny i dynamiczny.
Statyczny - administrator ręcznie wpisuje wszystkie adresy to tablicy routingu. Najprostszą formą budowania informacji o topologii sieci są ręcznie podane przez administratora trasy definiujące routing statyczny. Przy tworzeniu takiej trasy wymagane jest jedynie podanie adresu sieci docelowej, interfejsu, przez który pakiet ma zostać wysłany oraz adresu IP następnego routera na trasie.
Zalety
Wady
Dynamiczny - routery samodzielnie zbierają informacje i aktualizują zapisy w tablicy.
Ponieważ statyczne systemy trasowania nie mogą reagować na zmiany w sieci, to generalnie nie są one przydatne do stosowania w sieciach dużych, gdzie zmiany następują praktycznie ciągle. Dlatego większość obecnie stosowanych algorytmów trasowania to algorytmy dynamiczne, dostosowujące się do zmiennych warunków występujących w sieci, na drodze analizy aktualizujących komunikatów trasowania. W wypadku, gdy aktualizujący komunikat trasowania wskazuje, że w sieci wystąpiły zmiany, oprogramowanie trasujące ponownie oblicza trasy i wysyła do routerów nowe komunikaty aktualizujące. W ślad za tym komunikaty, przenikając przez sieć, stymulują routery do uruchomienia algorytmów trasowania i zmieniają ich tablice trasowania.
Protokoły trasowania dynamicznego są wykorzystywane przez routery do pełnienia trzech podstawowych funkcji:
Podział protokołów:
Protokoły wektora odległości:
Trasowanie może być oparte na algorytmach wektora odległości (nazywanych również algorytmami Bellmana-Forda). Nazwa pochodzi stąd, iż poszczególne routery prezentowane są jako wektory zawierające dwie informacje: dystans oraz wektor wyznaczający kierunek. Dystans opisuje całkowity koszt/metrykę danej trasy i wyrażany jest za pomocą pewnej liczby, natomiast Kierunek definiowany jest poprzez adres następnego skoku.
Etapy działania protokołu:
Router nie widzi poza swojego sąsiada i informacje o innych sieciach, nieprzyłączonych do niego bezpośrednio, uzyskuje tylko dzięki nim. Nazywa się to routingiem przez plotkowanie.

Przykładowe protokoły: RIP, EBGP.
Algorytmy trasowania na podstawie stanu łącza, ogólnie określane jako protokoły "najpierw najkrótsza ścieżka" (ang. SPF shortest path first), utrzymują złożoną bazę danych opisującą topologię sieci. W odróżnieniu od protokołów wektora odległości, protokoły stanu łącza zbierają i przechowują pełną informację na temat routerów sieci, a także o sposobie ich połączenia.
W protokołach stanu łącza każdy router przechowuje kompletną bazę danych o topologii sieci z informacjami o koszcie pojedynczych ścieżek w obrębie sieci oraz o stanie połączeń. Informacje te kompletowane są poprzez rozsyłanie tzw. pakietów LSA (Link-State Advertisement) o stanie łączy.
Przykładowe protokoły: OSPF, IS-IS, IDRP
Ostatnią formą trasowania dynamicznego jest praca hybrydowa. Choć istnieją "otwarte" zrównoważone protokoły hybrydowe, ta forma trasowania jest niemal całkowicie związana z zastrzeżonym produktem jednej firmy Cisco Systems, Inc. Protokół o nazwie EIGRP (ang. Enhanced Interior Gateway Routing Protocol) został zaprojektowany z zamiarem połączenia najlepszych cech protokołów opartych na wektorze odległości i stanie łącza, przy jednoczesnym ominięciu ich ograniczeń wydajności i innych wad.
Potrzebna informacja:
System autonomiczny – grupa sieci i routerów pod wspólną administracją (korporacje, uczelnie). Routery wewnątrz systemu autonomicznego dowolnie zarządzają trasami. Każdy system autonomiczny wybiera router lub routery przeznaczone do komunikacji z innymi systemami autonomicznymi. Odpowiadają one za przekazywanie informacji o osiągalności sieci wewnątrz „swojego” systemu do innych systemów.
Routery odpowiedzialne za komunikację z innymi systemami autonomicznymi nazywane są routerami zewnętrznymi albo brzegowymi (exterior gateways), routery działające wewnątrz systemu – wewnętrznymi (interior gateways).
Zewnętrzne:
EGP(Exterior Gateway Protocol)
Inny protokoł tego typu: (E) BGP (Exterior Border Gateway Protocol)
Wewnętrzne:
Grupę protokołów używanych przez routery wewnątrz systemu autonomicznego określa się nazwą IGP (Interior Gateway Protocols)
W jaki sposób algorytmy trasowania decydują o tym, że jedna trasa jest preferowana bardziej niż inna? Rozróżnia się obecnie następujące miary trasowania:
Długość ściężki jest najczęściej używaną miarą trasowania. Niektóre protokoły trasowania zezwalają administratorowi sieci na arbitralne przypisywanie kosztów każdemu łączu sieciowemu. W takim wypadku koszt ścieżki jest sumą kosztów związanych z każdym łączem składającym się na ścieżkę. Inne protokoły trasowania natomiast używają miary hop count, rozumianej jako liczba przejść pakietu przez urządzenia intersieciowe - np. routery - od stacji nadawczej do stacji odbiorczej.
Niezawodność, w kontekście algorytmów trasowania, odnosi się do skuteczności każdego łącza (określanego liczbą przekłamanych bitów). Niektóre łącza mogą ulegać uszkodzeniom częściej od innych. Po uszkodzeniu sieci niektóre łącza można naprawić szybciej i prościej niż inne.
Opóźnienie trasowania oznacza czas potrzebny do przesłania pakietu od stacji nadawczej do stacji odbiorczej w intersieci.
Szerokość pasma odnosi się do dostępnej pojemności ruchu w określonym łączu
Obciążenie to stopień zajętości zasobu sieciowego, np. routera. Obciążenie zależy od wielu czynników, np. stopnia wykorzystania procesora czy liczby pakietów przetwarzanych w czasie jednej sekundy.
Koszt komunikacji jest ważną miarą trasowania, przede wszystkim dlatego, że niektóre firmy nie dbają o wydajność. Nawet wtedy, gdy opóźnienia są duże, przesyłają pakiety przez własne linie zamiast korzystać z sieci publicznych, za które się płaci tylko w czasie ich używania.
Ogółny Zarys
Usługi nazewnicze wykorzystywane są do dystrybuowania informacji. One tłumaczą nazwy hostów na adresy IP. Internetowym standardem jest DNS, ale w pewnych sytuacjach wykorzystywane są NIS i WINS.
DNS(ang. Domain Name System, system nazw domenowych) to system serwerów oraz protokół komunikacyjny zapewniający zamianę adresów znanych użytkownikom Internetu na adresy zrozumiałe dla urządzeń tworzących sieć komputerową. Dzięki wykorzystaniu DNS nazwa mnemoniczna, np. pl.wikipedia.org, może zostać zamieniona na odpowiadający jej adres IP, czyli 145.97.39.135.
Adresy DNS składają się z domen internetowych rozdzielonych kropkami. Dla przykładu w adresie Wikipedii org oznacza domenę funkcjonalną organizacji, wikipedia domenę należącądo fundacji Wikimedia, a pl polską domenę w sieci tej instytucji. W ten sposób możliwe jest budowanie hierarchii nazw, które porządkują Internet.
Strona Techniczna
Podstawą technicznego systemu DNS jest ogólnoświatowa sieć serwerów przechowujących informacje na temat adresów domen. Każdy wpis zawiera nazwę oraz odpowiadającą jej wartość, najczęściej adres IP. System DNS jest podstawą dla rozwiązywania nazw hostów w Internecie.
DNS to również protokół komunikacyjny opisujący sposób łączenia się klientów z serwerami DNS. Częścią specyfikacji protokołu jest również zestaw zaleceń, jak aktualizować wpisy w bazach domen internetowych. Na świecie jest wiele serwerów DNS, które odpowiadają za obsługę poszczególnych domen internetowych. Domeny mają strukturę drzewiastą, na szczycie znajduje się 13 głównych serwerów (root servers) obsługujących domeny najwyższego poziomu (TLD – top level domains).
Serwery najwyższego poziomu z reguły posiadają tylko odwołania do odpowiednich serwerów DNS odpowiedzialnych za domeny niższego rzędu, np. serwery główne (obsługujące między innymi TLD.com) wiedzą, które serwery DNS odpowiedzialne są za domenę example.com. Serwery DNS zwracają nazwę serwerów odpowiedzialnych za domeny niższego rzędu. Możliwa jest sytuacja, że serwer główny odpowiada, że dane o domenie example.com posiada serwer dns.example.com. W celu uniknięcia zapętlenia w takiej sytuacji serwer główny do odpowiedzi dołącza specjalny rekord (tak zwany glue record) zawierający także adres IP serwera niższego rzędu (w tym przypadku dns.example.com).
Wewnątrz każdej domeny można tworzyć tzw. subdomeny - stąd mówimy, że system domen jest 'hierarchiczny'. Przykładowo wewnątrz domeny .pl utworzono wiele domen:
Nazwy domen i poszczególnych komputerów składają się z pewnej liczby nazw, oddzielonych kropkami. Ostatnia z tych nazw jest domeną najwyższego poziomu. Każda z tych nazw może zawierać litery, cyfry lub znak '-'. Od niedawna w nazwach niektórych domen można używać znaków narodowych (IDN) takich jak 'ą' czy 'ż', ale większośćwspółczesnych programów nie przewiduje możliwości wykorzystania takich funkcji. Wewnątrz każdej z poddomen można tworzyć dalsze poddomeny, np. w domenie 'wikipedia.org' można utworzyć domenępl.wikipedia.org.
DNS, jako system organizacyjny, składa się z dwóch instytucji - IANA i ICANN. Nadzorująone ogólne zasady przyznawania nazw domen i adresów IP. Jednak te dwie instytucje nie sąw stanie zajmować się całym światem i dlatego cedują swoje uprawnienia na szereg lokalnych instytucji i firm.
Najważniejsze cechy DNS:
Rodzaje zapytań DNS
Zmusza serwer do znalezienia wymaganej informacji lub zwrócenia wiadomości o błędzie. Ogólną zasadą jest, że zapytania od resolwera (program, który potrafi wysyłać zapytania do serwerów DNS) do serwera są typu rekurencyjnego, czyli resolwer oczekuje podania przez serwer adresu IP poszukiwanego hosta. Wykonywanie zapytań rekurencyjnych pozwala wszystkim uczestniczącym serwerom zapamiętać odwzorowanie (ang. DNS caching), co podnosi efektywność systemu.
Wymaga od serwera jedynie podania najlepszej dostępnej mu w danej chwili odpowiedzi, przy czym nie musi on łączyć się jeszcze z innymi serwerami. Zapytania wysyłane pomiędzy serwerami są iteracyjne, przykładowo wiarygodny serwer domeny org nie musi znać adresu IP komputera www.pl.wikipedia.org, podaje więc najlepszą znaną mu w tej chwili odpowiedź, czyli adresy serwerów autorytatywnych dla domeny wikipedia.org
Odpowiedzi na zapytania
Dotyczące domeny w strefie, nad którą dany serwer ma zarząd, pochodzą one bezpośrednio z bazy danych serwera; jest to pozytywna odpowiedź zwracana do klienta, która w komunikacie DNS zawiera ustawiony bit uwierzytelniania (AA – Authoritative Answer) wskazujący, że odpowiedź została uzyskana z serwera dokonującego bezpośredniego uwierzytelnienia poszukiwanej nazwy
Dane które zwraca serwer pochodzą spoza zarządzanej przez niego strefy; odpowiedzi nieautorytatywne są buforowane poprzez serwer przez czas TTL wyrażony w sekundach, wyspecyfikowany w odpowiedzi, a następnie po upływie czasu są usuwane
Komunikaty DNS
Zapytania i odpowiedzi DNS są najczęściej transportowane w pakietach UDP. Każdy komunikat musi się zawrzeć w jednym pakiecie UDP (standardowo 512 oktetów, ale wielkość tę można zmieniać pamiętając również o ustawieniu takiej samej wielkości w MTU – Maximum Transmission Unit). W innym przypadku przesyłany jest protokołem TCP i poprzedzony dwubajtową wartością określającą długość zapytania i długość odpowiedzi (bez wliczania tych dwóch bajtów).
NAGLÓWEK - (Header)
ZAPYTANIE - (Question) do serwera nazw
ODPOWIEDŻ - (Answer) zawiera rekordy będące odpowiedzią
ZWIERZCHNOŚĆ - (Authority) wskazuje serwery zwierzchnie dla domeny
DODATKOWE - (Additional) sekcja informacji dodatkowych
| Ex. 1 | Ex. 2 | Ex. 3 |
|---|---|---|
| Ts | Ts | Ts |
Wirtualna sieć lokalna, VLAN (ang. virtual local area network) - sieć komputerowa wydzielona logicznie w ramach innej, większej sieci fizycznej.
Wirtualne sieci lokalne (Virtual Local Area Networks, VLANs) umożliwiają podział większej fizycznej sieci komputerowej na logiczne, odizolowane segmenty. Kształtowanie przepływu ruchu między sieciami VLAN odbywa się w warstwie 3. modelu OSI.
Virtual LAN dzieli fizyczne łącza na logiczne segmenty, ale sposób zaprojektowania wirtualnej sieci lokalnej zależy od administratora, a raczej przyjętych w organizacji założeń w zakresie kształtowania przepływu ruchu oraz wymaganego poziomu bezpieczeństwa. W ten sposób na jednym fizycznym przełączniku można utworzyć dwie (lub więcej) odizolowane od siebie sieci lokalne.
Tylko urządzenia przynależące do tej samej sieci VLAN mogą komunikować się ze sobą, każda sieć VLAN tworzy bowiem niezależną domenę rozgłoszeniową. Przełączniki przekazują ruch transmisji pojedynczej (unicast), grupowej (multicast) i rozgłoszeniowej (broadcast) tylko w ramach jednego segmentu sieci LAN. Poza izolacją segmentów sieci podejście to pozwala też ograniczyć zalewanie portów przełącznika rozgłoszeniami z protokołów ARP i DHCP, które nigdy nie przekraczają granic sieci VLAN.
Mechanizm routingu między VLAN, choć wymaga zastosowania dodatkowych urządzeń, pozwala kształtować przepływy ruchu między poszczególnymi segmentami sieci komputerowej. Mowa tutaj o kontroli dostępu, filtrowaniu ruchu na zaporze sieciowej czy zapewnianiu jakości usług (QoS).
Praktyczne zastosowanie
Sieć VLAN może służyć do segmentacji według struktury organizacyjnej. W instytucjach publicznych komputery pracowników działów finansowych i HR nie powinny komunikować się ze względów bezpieczeństwa z urządzeniami pozostałego personelu biurowego. Z kolei w firmie produkcyjnej technologia VLAN może odizolować ruch sieci komputerowej udostępnianej pracownikom biurowym od sieci komputerowej wykorzystywanej w wydziałach produkcyjnych na potrzeby zbierania danych i sterowania maszynami.
Inne praktyczne zastosowanie sieci VLAN to segmentacja ruchu sieciowego ze względu na jego typ. Podejście to sprawdzi się w każdej instytucji, nawet gdy nie ma jawnej potrzeby izolowania ruchu według struktury organizacyjnej. Oddzielne VLAN stosuje się dla serwerów, punktów końcowych (stacje robocze, laptopy), drukarek, urządzeń mobilnych (strategia BYOD), telefonów VoIP, sieci Wi-Fi dla gości, sieci zarządzania (management) czy strefy DMZ.
Protokół IEEE 802.1Q
VLAN to wydzielona logicznie sieć komputerowa warstwy 2. (łącza danych) modelu OSI. Grupuje logicznie porty jednego lub wielu przełączników sieciowych niezależnie od ich położenia. Podstawowym, powszechnie stosowanym protokołem oznaczania ramek i trunkingu jest IEEE 802.1Q. Protokół ten, nazywany także Dot1q, stał się branżowym standardem definiującym sposób obsługi VLAN w sieciach Ethernet.
Działanie sieci VLAN bazuje na dodawaniu 4-bajtowych znaczników (tagów) wewnątrz nagłówka ramek Ethernet, które pozwalają urządzeniom sieciowym sterować przepływem ruchu. Znacznik ten, o nazwie 802.1Q Header, umieszczany jest między polem adresu źródłowego (Source MAC) a polem wskazującym na typ ramki/długość (EtherType/Size). Pierwsze dwa bajty tego znacznika (Tag Protocol ID, TPID) mają stałą wartość 0x8100 i umożliwiają przełącznikowi odróżnienie znakowanej ramki 802.1Q od ramki nieznakowanej, która w tym miejscu miałaby pole EtherType/Size. Pozostałe dwa bajty (Tag Control Information, TCI) zawierają informacje służące do oznaczenia priorytetu ramki (definiowany w standardzie 802.1p), standardu sieci LAN (Ethernet lub Token Ring) oraz numeru wirtualnej sieci (VLAN ID), do której przynależy dana ramka. Wspomniane pole VLAN ID, stanowiące identyfikator sieci wirtualnej, ma długość 12 bitów i pozwala skutecznie przypisać ramkę do właściwego segmentu VLAN. W rezultacie na przełączniku można zdefiniować maksymalnie do 4096 sieci VLAN, z czego dwie są zarezerwowane do innych celów, a VLAN 1 pełni funkcję sieci natywnej.
W tym miejscu warto też wspomnieć o innym protokole znakowania i trunkingu. InterSwitch Link (ISL) to własnościowy protokół Cisco używany w przełącznikach tej firmy. Oryginalna ramka Ethernet pozostaje niezmieniona, jest bowiem kapsułkowana w ramce ISL, której nagłówek zawiera znacznik VLAN ID. Protokół ISL został uznany za przestarzały, nie powinien być dalej używany. Co więcej, nie jest wspierany przez najnowsze przełączniki Cisco.
Punkty końcowe mogą komunikować się ze sobą w ramach jednej sieci VLAN. Przekazywanie ruchu sieciowego między sieciami VLAN wymaga zastosowania routera lub przełącznika działającego w warstwie 3. (sieci) modelu OSI.
| Ex. 1 | Ex. 2 | Ex. 3 |
|---|---|---|
| Ts | Ts | Ts |
Są 2 rodzaje optymalizacji:
Pierwsza z podanych klasyfikacji wyróżnia optymalizację statyczną i optymalizację dynamiczną. Optymalizacja statyczna polega na znalezieniu „najlepszego” planu wykonania zapytania, przed rozpoczęciem wykonywania zapytania. W trakcie realizacji zapytania plan wykonania zapytania nie ulega już zmianie – stąd nazwa optymalizacja statyczna. Optymalizacja dynamiczna polega na znalezieniu „najlepszego” planu wykonania zapytania, przed rozpoczęciem wykonywania zapytania, ale później, w trakcie wykonywania zapytania jego plan wykonania może ulęgać zmianie. Aktualnie, komercyjne systemy baz danych zapewniają jedynie optymalizację statyczna, choć efektywność takiej optymalizacji jest najczęściej niższa aniżeli efektywność optymalizacji dynamicznej. Optymalizacja dynamiczna jest jednak znacznie bardziej kosztowna. Druga z podanych klasyfikacji wyróżnia optymalizację pojedynczego zapytania oraz jednoczesną optymalizację wielu zapytań. W przypadku optymalizacji pojedynczego zapytania, optymalizacji podlega tylko jedno zapytanie. W przypadku jednoczesnej optymalizacji wielu zapytań, częściowe wyniki wykonania jednego zapytania mogą być wykorzystane przez wiele innych zapytań, co prowadzi do minimalizacji czasu wykonania zbioru zapytań. W chwili obecnej systemy komercyjnych baz danych zapewniają jedynie optymalizację pojedynczego zapytania.
Ogółny proces optymalizacji zapytań:
W wyniku zastowania transformacji algebraicznych uzyskujemy zbiór najlepszych planów wykonania pojedynczych bloków zapytania. Pozostaje jeszcze problem połączenia bloków, w szczególności, problem zdefiniowania porządku wykonywania operacji połączenia. Wybór kolejności wykonywania operacji połączenia, tzn. wybór uszeregowania operacji połączenia, kończy proces optymalizacji zapytania.
Dekompozycja
Pierwszą fazą przetwarzania zapytania jest dekompozycja zapytania. Celem procesu dekompozycji zapytania jest transformacja zapytania wyrażonego w języku wysokiego poziomu na wyrażenie algebry relacji i weryfikacja syntaktycznej i semantycznej poprawności zapytania. Proces dekompozycji składa się z następujących etapów:
Analiza zapytania
Celem etapu analizy jest analiza syntaktyczna poprawności zapytania. W skład tej analizy wchodzi weryfikacja poprawności atrybutów i relacji (czy w bazie danych występują wyspecyfikowane w zapytaniu relacje i atrybuty, czy zapytanie poprawnie specyfikuje typy danych).
Następnie, zapytanie wyrażone w języku SQL jest transformowane do postaci reprezentacji wewnętrznej (wyrażenia algebry relacji, które można zapisać w postaci drzewa, jak na przykładzie poniżej), bardziej adekwatnej do procesu dalszego przetwarzania zapytania.
Select *
From Employee E, Department D
Where E. deptId = D. DeptId
And E.position = 'manager' and D.location = ‘London';

Normalizacja
Kolejnym etapem fazy dekompozycji jest normalizacja zapytania. Celem etapu normalizacji zapytania jest przekształcenie wewnętrznej reprezentacji zapytania do znormalizowanej postaci koniunkcyjnej lub dysjunkcyjnej. W fazie tej sekwencja predykatów selekcji jest przekształcana do normalnej postaci koniunkcyjnej lub normalnej postaci dysjunkcyjnej. Postać dysjunkcyjna jest, najczęściej, mniej efektywna, gdyż wymaga niezależnego wartościowania poszczególnych składowych wyrażenia. Przykłady postaci koniunkcyjnej i dysjunkcyjnej wyrażenia zapytania:

Analiza semantyczna zapytania(1)
Kolejnym, ważnym, etapem dekompozycji zapytania jest etap analizy semantycznej
zapytania. Celem analizy semantycznej zapytania jest odrzucenie niepoprawnie
sformułowanych lub sprzecznych zapytań. Zapytanie jest niepoprawnie sformułowane,
jeżeli jego elementy składowe nie prowadzą do generacji wyniku. Zapytanie jest
sprzeczne, jeżeli jego predykaty nie mogą być spełnione przez żadną krotkę w bazie
danych. Przykładem klauzuli, która jest sprzeczna jest wyrażenie:
position = ‘manager’
and position = ‘assistant’.
Zakładając, że baza danych jest w 1NF, nie istnieje w bazie danych żadna krotka, któraby
jednocześnie spełniała oba predykaty. Wartość sprzecznej klauzuli interpretujemy jako
wartość FALSE. W związku z tym, wyrażenie zawierające sprzeczna klauzulę można
uprościć.
Przykładowo, wyrażenie
(position = ‘manager’ and position = ‘assistant’) or salary > 1000;
ze względu na sprzeczność klauzuli : „position = ‘manager’ and position = ‘assistant’”
można uprościć do postaci „salary > 1000”
Analiza semantyczna zapytania(2)
Niestety, algorytmy oceny poprawności semantycznej zapytań istnieją tylko dla pewnej klasy zapytań, nie zawierających dysjunkcji i negacji. W jaki sposób rozwiązywany jest problem zapytań niepoprawnie sformułowanych oraz zapytań sprzecznych? Rozwiązanie problemu zapytań niepoprawnie sformułowanych opiera się na konstrukcji tak zwanego grafu połączenia relacji. W grafie tym, wierzchołki odpowiadają relacjom, natomiast luki odpowiadają operacjom połączenia wyspecyfikowanych w zapytaniu. Dodatkowo, graf połączenia relacji zawiera wierzchołek reprezentujący wynik zapytania. Jeżeli graf połączenia relacji nie jest spójny, to zapytanie jest niepoprawnie sformułowane.
Rozwiązanie problemu zapytań niepoprawnie sformułowanych opiera się na konstrukcji tak zwanego grafu połączeń atrybutów.
Przykłady tworzenia tych grafów (str: 10-12)
Kolejnym etapem fazy dekompozycji jest upraszczanie zapytań. Celem tego etapu jest identyfikacja wyrażeń redundantnych, eliminacja wspólnych podwyrażeń, i transformacja zapytania do równoważnej postaci, ułatwiającej dalsze przekształcanie zapytania. Transformacja zapytania do postaci równoważnej polega na zastosowaniu znanych reguł algebry relacji.
Kolejnym etapem fazy dekompozycji jest etap restrukturyzacji, czy tez transformacji zapytania. Zanim jednak przejdziemy do przedstawienia podstawowych reguł transformacji, wróćmy na chwilę do problemu konstrukcji podstawowych bloków zapytania. Tradycyjne podejście do konstrukcji bloków zapytania opera się na zastosowaniu transformacji algebraicznych, jednakże, zbiór stosowanych transformacji różni się zasadniczo dla różnych systemów komercyjnych.
Co więcej, nie wszystkie transformacje gwarantują minimalizację czasu wykonania danego bloku. W ostatnim czasie, coraz częściej, konstrukcja bloków opiera się na optymalizacji kosztowej, w której, dla każdego bloku, konstruujemy możliwe plany wykonania danego bloku i szacujemy koszt i rozmiar wykonania każdego planu. Ostatecznie wybierany jest plan wykonania o najniższym szacowanym koszcie. Do zakończenia procesu optymalizacji pozostaje jeszcze znalezienie najlepszego drzewa operacji połączenia, łączącego wyniki wykonania bloków zapytania. Tradycyjne podejście do problemu znajdowania najlepszego drzewa operacji połączenia (nazywane często podejściem w stylu systemu R) polega na zastosowaniu algorytmu programowania dynamicznego.
Każdy plan wykonania zapytania jest częściowo uporządkowanym zbiorem operacji. W skład tego zbioru operacji wchodzą: operacja skanowania, selekcji, projekcji, połączenia, produktu kartezjańskiego, operacje grupowania i agregacji. Problem znalezienia najlepszego planu wykonania zapytania obejmuje, z jednej strony, określenie kolejności wykonania operacji wchodzących w skład zapytania, z drugiej, określenia metody wykonania poszczególnych operacji. Przykładowo, mamy dwie metody dostępu do relacji: bezpośrednie skanowanie (odczyt) relacji lub dostęp do relacji poprzez skanowanie indeksu założonego na relacji. Podstawowa reguła optymalizacji mówi, że wszystkie operacje unarne (projekcja i selekcja) należy przesunąć w dół drzewa zapytania, tzn. wykonywać w pierwszej kolejności. Operacje te charakteryzują się silną własnością redukcji (filtrowania) przetwarzanych danych. Redukując rozmiar przetwarzanych danych, operacje unarne prowadzą do poprawy efektywności wykonywania operacji binarnych. Dlatego, operacje binarne (połączenie, produkt kartezjański) należy przesunąć w kierunku korzenia drzewa zapytania. Dla operacji binarnych, np. połączenia, poza określeniem kolejności ich wykonywania, należy wybrać również metodę ich wykonania (dla połączenia - nested loop, sort-merge, hash-join). Najczęściej, na końcu planu wykonania zapytania znajdują się operacje grupowania i agregacji.
Reguły transformacji oparte na algebrze relacji (Strony: 17-20)
Ważne
Zapytania zawierające skorelowane podzapytania zagnieżdżone są kosztowne w realizacji, gdyż wymagają sprawdzenia, dla każdej krotki zapytania zewnętrznego, czy spełniony jest dla tej krotki warunek podzapytania skorelowanego. Klasyczna metoda transformacji takich zapytań polega na przepisaniu zapytania w taki sposób, aby usunąć zagnieżdżenie (ang. unnesting). Usunięcie zagnieżdżenia polega na zastąpieniu zagnieżdżenia operacją połączenia.
Przykłady transformacji zagnieżdzionych zapytań (Strony: 21-26)
Zagadnienie optymalizacji jest zagadnieniem trudnym i istnieje bardzo wiele, specyficznych, reguł transformacji dla różnych typów zapytań. Co więcej, nie zawsze jest możliwe przetransformowanie zapytań w taki sposób, aby nie zawierało podzapytań (szczególnie dla podzapytań skorelowanych). W szczególnych przypadkach, gdy czas realizacji zapytania jest nieakceptowalny, można zastosować technikę redukcji rozmiarów relacji uczestniczących w zapytaniu opartą o sekwencję operacji półpołączenia. Technika ta jest wykorzystywana do optymalizacji zapytań rozproszonych w systemach rozproszonych baz danych.
Uwierzytelnianie (ang. authentication) - roces polegający na potwierdzeniu zadeklarowanej tożsamości podmiotu biorącego udział w procesie komunikacji. Celem uwierzytelniania jest uzyskanie określonego poziomu pewności, że dany podmiot jest w rzeczywistości tym, za który się podaje.
W systemach informatycznych stosuje się następujące rodzaje uwierzytelniania:



Klasyczne uwierzytelnianie użytkownika
W przypadku wielu współczesnych środowisk informatycznych, systemów operacyjnych lub systemów zarządzania bazami danych, funkcjonuje klasyczny mechanizm uwierzytelniania poprzez hasło. Proces uwierzytelniania rozpoczyna klient żądając zarejestrowania w systemie (login). Serwer pyta o identyfikator (nazwę) użytkownika, a następnie o hasło i decyduje o dopuszczeniu do sieci. W większości przypadków nazwa użytkownika i hasło są przesyłane tekstem jawnym, co stanowić może kolejny problem zapewnienia poufności, jaką właśnie mamy osiągnąć stosując opisywany mechanizm. Stąd też takie klasyczne podejście nadaje się do wykorzystania jedynie w ograniczonej liczbie przypadków, kiedy np. mamy uzasadnioną skądinąd pewność wykluczenia możliwości podsłuchu danych uwierzytelniających.
Hasła nie są najefektywniejszą, ani najbezpieczniejszą formą weryfikacji tożsamości użytkownika, z następujących powodów:
Zdalne potwierdzanie tożsamości
W środowisku sieci TCP/IP wypracowano mechanizm prostego potwierdzania tożsamości użytkownika, który żąda zdalnego uwierzytelniania. W tym celu powstał standard RFC 1413 opisujący usługę o nazwie identd. Niezależnie od jej aktualnej przydatności i powszechności warto zdawać sobie sprawę z istoty jej działania, którą łatwo opisać w następujący sposób:

Należy też zdawać sobie sprawę z potencjalnych zagrożeń jakie niesie udostępnianie przez usługę ident informacji o przynależności procesów dokonujących komunikacji sieciowej (nie tylko klientów). W standardzie RFC 1413 oraz w praktycznych implementacjach nie realizuje się bowiem uwierzytelniania podmiotu żądającego informacji z tej usługi, może ona być zatem również nadużyta przez potencjalnego włamywacza.
Procedury uwierzytelniania jednokrotnego są częściowym rozwiązaniem problemu ochrony danych uwierzytelniających przed złamaniem w systemie wielozasobowym, np. sieci komputerowej z wieloma serwerami.
Ideą procedury uwierzytelniania jednokrotnego jest minimalizacja ilości wystąpień danych uwierzytelniających w systemie - hasło powinno być podawana jak najrzadziej. Zgodnie z tą zasadą, jeśli jeden z komponentów systemu (np. system operacyjny) dokonał pomyślnie uwierzytelniania użytkownika, pozostałe komponenty (np. inne systemy lub zarządcy zasobów) ufać będą tej operacji i nie będą samodzielnie wymagać podawania ponownie danych uwierzytelniających. Przy tym jest możliwe teoretycznie, że wszystkie komponenty samodzielnie korzystają z odmiennych mechanizmów uwierzytelniana. Wówczas, dodatkowo po pierwszorazowym uwierzytelnieniu użytkownika, system może oddelegować specjalny moduł do przechowywania odrębnych danych uwierzytelniających użytkownika i poświadczania w przyszłości jego tożsamości wobec innych komponentów systemu.
chemat SSO przedstawia poniższy rysunek. W przedstawionej na rysunku sytuacji tylko jeden serwer dokonuje uwierzytelniania klienta, reszta ufa uwierzytelnianiu dokonanemu przez ten serwer.

Istota wykorzystania haseł jednorazowych wynika zamiaru ochrony ich przed przechwyceniem i nieautoryzowanym wykorzystanie, w przyszłości. Jednak nie polega na zapewnieniu ich poufności w transmisji lecz na uczynieniu ich de facto bezwartościowymi po przechwyceniu. Opiera się na, jak sama nazwa wskazuje, tylko użyciu danej postaci hasła tylko raz. Hasła jednorazowe mają przy każdym kolejnym uwierzytelnieniu inną postać. Raz przechwycone hasło jednorazowe nie jest przydatne, bowiem przy kolejnym uwierzytelnieniu będzie obowiązywać już inne. Komunikacja między podmiotami procesu uwierzytelniania może być zatem jawna. Stosujące takie hasła procedury uwierzytelniania muszą jedynie oferować brak możliwości odgadnięcia na podstawie jednego z haseł, hasła następnego.
Hasła jednorazowe generowane są przy pomocy listy haseł, synchronizacji czasu lub metody zawołanie-odzew. Dostępne są najczęściej w następujących postaciach: listy papierowe, listy-zdrapki, tokeny programowe i tokeny sprzętowe.
Lista haseł
Listy haseł to najprostsza i najtańsza metoda identyfikacji metodą haseł jednorazowych. Użytkownik otrzymuje listę zawierająca ponumerowane hasła. Ta sama lista zostaje zapisana w bazie systemu identyfikującego. W trakcie logowania użytkownik podaje swój identyfikator, a system prosi o podanie hasła z odpowiednim numerem. Klient za każdym razem posługuje się kolejnym niewykorzystanym hasłem z listy.

Metoda synchronizacji czaswoej
W metodzie z synchronizacją czasu (time synchronization) klient generuje unikalny kod w funkcji pewnego parametru X użytkownika (identyfikatora, kodu pin, hasła, numeru seryjnego karty identyfikacyjnej) oraz bieżącego czasu. Serwer następnie weryfikuje otrzymany od klienta kod korzystając z identycznej funkcji (z odpowiednią tolerancją czasu).

Metoda "Zawołanie-Odzew"
Natomiast w metodzie zawołanie-odzew (challenge-response) serwer pyta o nazwę użytkownika, a następnie przesyła unikalny ciąg („zawołanie"). Klient koduje otrzymany ciąg (np. swoim hasłem lub innym tajnym parametrem pełniącym rolę klucza) i odsyła jako „odzew". Serwer posługując się identycznym kluczem weryfikuje poprawność odzewu.

Metoda Tokenów
Tokeny programowe to specjalne programy generujące hasła. W zależności od implementacji program na podstawie kwantu czasu lub zawołania serwera generuje hasło jednorazowe, które weryfikuje serwer.
Token sprzętowy jest małym przenośnym urządzeniem spełniającym wszystkie funkcje tokenu programowego.
Pewną ciekawostką zyskującą na popularności jest wykorzystanie telefonu komórkowego w uwierzytelnianiu za pomocą haseł jednorazowych. Cały proces polega przesłaniu hasła jednorazowego z serwera na telefon w postaci wiadomości SMS. W tym przypadku rola telefonu jako swoistego tokena sprowadza się tylko do medium odbierającego i wyświetlającego dane.
Inne mechanizmy uwierzytelniania
Do uwierzytelniania użytkowników można wykorzystać również przedmioty, których posiadaniem musi się wykazać uwierzytelniany. Mogą to być np. karty magnetyczne, karty elektroniczne czy tokeny USB. Ponadto, w przypadku ludzi, można posłużyć się również cechami osobowymi wynikającymi z odmienności parametrów niektórych naturalnych składników organizmu (uwierzytelnianie biometryczne), takich jak m.in.:
Autoryzacja i kontrola dostępu zaczyna się tam, gdzie kończy się uwierzytelnianie. Kiedy podmiot zabezpieczeń SP (Security Principal) podejmuje próbę uzyskania dostępu do chronionego obiektu lub usługi, proces autoryzacji przejmuje jego tożsamość i używa jej do określenia jego uprawnień.
Zadania autoryzacji i kontroli dostępu legalnych użytkowników należą do podstawowych funkcji systemów operacyjnych czy systemów zarządzania bazą danych oraz środowisk przetwarzania rozproszonego. W większości przypadków te funkcje są realizowane podobnie.
Jeżeli SP próbuje uzyskać dostęp (np. do pliku na serwerze WWW), usługa autoryzacji kwerenduje bazę danych, aby określić, jakie uprawnienia związane z tym plikiem ma SP. System kontroli dostępu jest programem lub procesem egzekwującym uprawnienia i przywileje. Generalnie, część autoryzacyjna systemu określa, że SP może tylko czytać dany plik, a system kontroli dostępu w rzeczywistości zapewnia, że nie może tego pliku zmodyfikować.
Modele kontroli dostępu opisują ogólne metody używane w poszczególnych domenach bezpieczeństwa do kontroli dostępu na styku SP i żądanej usługi czy obiektu.
Główna różnica między modelem dostępu RBAC a DAC polega na tym, że grupy DAC mają na ogół określać ogólną przynależność (np. zespół działu kadr), podczas gdy wyznacznikiem RBAC są działania (np. wykonywane przez pracownika działu kadr, działu płac itp.).
Wiele modeli RBAC (w tym sporo zaimplementowanych jako warstwa nad systemami DAC) dopuszcza tylko szczególne uprawnienia w trakcie wykonywania przez SP koniecznych działań. I tak np. w tym modelu pracownik zajmujący się wypłatami ma dostęp do bazy danych płac tylko wtedy, gdy korzysta z aplikacji płacowej.
W domenie bezpieczeństwa opartej na DAC pracownik działu płac będzie miał prawdopodobnie uprawnienia do zapisów oraz odczytu całej bazy danych, i te uprawnienia będą stałe oraz niezależne od aplikacji.
Systemy RBAC są dużo bardziej bezpieczne. Preferuje je większość ekspertów ds. bezpieczeństwa, ale również wymagają znacząco większego wysiłku po stronie administrowania, podejmowania decyzji o uprawnieniach, określania delegacji ról. W codziennym użytkowaniu RBAC wymaga większej automatyzacji i stosowania globalnych praktyk zarządzania.
W praktyce rzadko można spotkać domenę bezpieczeństwa, gdzie zastosowano tylko jeden model kontroli dostępu. System operacyjny Windows jest zbudowany wokół DAC, ale już w systemie Vista Microsoft dodał MAC (stosując obowiązkową kontrolę integralności), a RBAC jest dostępny na poziomie sieciowym w Active Directory. Wiele domen opartych na DAC i RBAC umożliwia także klasyfikowanie (etykietowanie) danych, podobnie jak systemy oparte na MAC, co pomaga ustalić właściwe uprawnienia i inne zabezpieczenia, które mają być stosowane na kolejnym poziomie ochrony ważnych danych.
Aby zapewnić odpowiedni poziom bezpieczeństwa, niezbędne jest rejestrowanie pomyślnych lub podejmowanych prób dostępu, a także działań po uzyskaniu dostępu. Rozliczanie jest zazwyczaj uważane za bardziej ogólną metodę rejestrowania niż audyt. System rozliczeniowy może rejestrować tylko pojedyncze pomyślne logowania (na sesję), liczbę przesłanych danych lub całkowity czas aktywności sesji. Z audytem wiąże się dużo bardziej szczegółowy poziom kontroli, pozwalający śledzić każdą wykonywaną przez SP akcję (lub próbę wykonania) - przeglądane lub modyfikowane pliki i foldery - oraz rejestrować czas wydarzenia.
Audyt i system rozliczania dodatkowo komplikują systemy współdzielone, tożsamości i hasła. Silny system AAA wymaga unikatowych tożsamości, aby każda indywidualna akcja mogła zostać zarejestrowana oddzielnie. Poziom rozliczalności i audytu może być ustawiony przez administratora, aczkolwiek zależy częściowo od systemu AAA i używanych protokołów. Dobry system rozliczania i audytu śledzi każdą akcję wykonywaną przez każdego SP - od tworzenia obiektu aż do jego usunięcia (włączając w to zdarzenia logowania i zmiany w dzienniku zdarzeń audytu). Więcej o tym tutaj (Strony 2-5)
Alfabet
Alfabetem nazywamy dowolny niepusty zbiór skooczony. Elementy alfabetu nazywami symbolami.
Słowa
Słowem
I Wyrażenia regularne
Def
Niech będzie dany zbiór Π = { ∅, λ ,+,· ,* ,( ,) } oraz alfabet Σ, przy czym Σ ∩ Π = ∅.
Wyrażeniem regularnym nad alfabetem Σ nazywamy każde słowo A ∊ (Σ, ∏)* spełniające jeden z poniższych warunków:
Rodzinę wyrażeo regularnych nad alfabetem Σ oznaczamy przez WR(Σ)
(lub WR jeśli nie będzie wątpliwości
dotyczących alfabetu)
II Języki regularne
Def
Niech będzie dany alfabet Σ oraz rodzina wyrażeń regularnych WR zdefiniowanych nad tym alfabetem. Każdemu wyrażeniu regularnemu A∊WR przyporządkowujemy język L(A) za pomocą definicji rekurencyjnej ze względu na budowę wyrażenia regularnego A:
Mówimy, że język L(A) jest językiem generowanym przez wyrażenie regularne A, natomiast o słowach należących do języka L(A) mówimy, że są generowane przez wyrażenie regularne A.
Def.
Językiem regularnym nazywamy każdy język formalny L nad danym alfabetem, dla którego istnieje wyrażenie regularne A takie, że: L=L(A) . Klasę języków regularnych oznaczamy przez JR.
Każdy język regularny może byd generowany przez wiele wyrażeo regularnych. Def. Mówimy, że wyrażenia regularne A i B są równoważne, gdy generują ten sam język, tzn
AUTOMAT SKOŃCZONY Rabina-Scotta
Automatem skończonym (typu Nas-labmda) nazywamy uporządkowaną piątkę
Język L złożony ze wszystkich słów akceptowanych przez automat skooczony M nazywamy generowanym przez automat M i oznaczamy przez L(M)
Gdzie:
Zbiór wszystkich języków generowanych przez automaty skończone oznaczamy symbolem ZJNAS-λ.
Przykład automatu skończonego:

Automatem skończonym type DAS nazywamy uporządkowaną piątke:
Język Lzłożony ze wszystkich słów akceptowanych przez automat M typu DAS nazywamy generowanym przez automat Mi oznaczamy przez L(M)
Zbiór wszystkich języków generowanych przez automaty typu DAS oznaczamy symbolem ZJDAS.
TW. 3
Jeżeli
jest automatem typu DAS, to generuje on język L wtedy i tylko wtedy, gdy automat
generuje język L`.
Przykład automatu typu DAS:

Ważne Tw. Zbiory języków generowanych przez automaty typu DAS i NAS-λ są sobie równe:
Def Gramatyką bezkontekstową nazywamy uporządkowaną czwórkę:
Def Językiem generowanym przez gramatykę G, nazywamy zbiór
Słowo A należy do języka L opisanego przez daną gramatykę G, jeśli istnieje ciąg produkcji prowadzący od symbolu zmiennej początkowej S do danego słowa. Mówimy wówczas, że słowo A jest wyprowadzone w gramatyce G.
Def
Językiem Bezkontekstowym nazywamy język, dla którego istnieje gramatyka bezkontekstowa generująca ten język.Zbiór języków generowanych przez gramatyki bezkontekstowe oznaczamy przez ZJB.
Def
Automatem ze Stosem(AZS) nazywamy uporządkowaną siódemkę:
Opisem chwilowym automatu M nazywamy każdą trójkę (S,A,B), gdzie:
Przykładowy auyomat ze Stosem:

Tw. 17
Zbiór języków akceptowanych przez automaty ze stosem jest równy zbiorowi języków bezkontekstowych.
Maszyny Turinga
Def. Maszyną Turinga (MT) nazywamy uporządkowany układ:
Def
Język L złożony ze wszystkich słów akceptowanych przez maszyne Turinga M nazywamy językiem generowanym przez maszynę M i oznaczamy przez L(M):
Zbiór wszystkich języków generowanych przez maszyny Turinga oznaczamy symbolem ZJMT i nazywamy rekursywnie przeliczalnymi.
Maszyne Turinga można przedstawić m in. za pomocą:
Przykład Maszyny Turinga

Przykład MT akceptującej słowa i MT obliczającej:

| MT | Języki |
|---|---|
| Maszyny Turinga Niedeterministyczne maszyny Turinga Wielotaśmowe maszyny Turinga Uniwersalna maszyna Turinga |
ZJRP zbiór języków rekursywnie przeliczalnych (rekurencyjnie przeliczalnych) |
| Właściwe MT - maszyny Turinga zatrzymująca się dla każdego słowa po skończonej ilości ruchów |
ZJRK Zbiór języków rekursywnych (rekurencyjnych) |
|
MT (automaty) liniowo ograniczone – maszyny Turinga w których <,> є Γ i głowica przesuwa się tylko między symbolami < i > wyznaczającymi początek i koniec słowa. |
ZJK Zbiór języków kontekstowych. |
Istnieje język formalny, który nie jest rekursywnie przeliczalnym, tzn. nie jest akceptowany przez żadną MT.# Zagadnienia na licencjat
Ciągiem nazywamy funkcję, której dziedziną jest zbiór liczb naturalnych lub jego skończony odcinek początkowy . Ciągiem liczbowym nazywamy ciąg, którego wyrazy są liczbami.
Liczbę nazywamy granicą ciągu nieskończonego , jeśli dla każdej liczby dodatniej istnieje taka liczba , że dla zachodzi nierówność:
Ciągiem zbieżnym (rozbieżnym) nazywamy ciąg, który posiada granicę (nie posiada granicy).
Jeśli ciąg posiada granicę to tylko jedną.
Każdy ciąg zbieżny jest ograniczony.
Przy założeniu, że ciągi i są zbieżne, zachodzą następujące wzory:
- (dla iloczynu i ilorazu też zachodzi)
Jeżeli ciąg jest zbieżny i , to .
Jeżeli ciąg jest zbieżny, to .
(Tw. o trzech ciągach): Jeśli , to ciąg jest zbieżny, przy czym .
Zmiana skończonej ilości wyrazów ciągu nie wpływa na jego zbieżność/granicę.
Podciąg ciągu zbieżnego jest zbieżny do tej samej granicy, co ciąg dany.
Po ludzku: Ciągi Cauchy'ego to takie ciągi, dla których odległości między wyrazami zmierzają do zera. Oznacza to, że wybierając dowolnie małą dodatnią liczbę rzeczywistą , można ustalić odpowiednio duży wskaźnik taki, że dowolne dwa wyrazy o wyższych wskaźnikach są odległe od siebie o mniej niż .
Ciąg jest zbieżny gdy jest ciągiem Cauchy’ego. (ale niekoniecznie odwrotnie).
Każdy ciąg Cauchy’ego jest ograniczony.
Macierzą (rzeczywistą) wymiaru m$\times$n, gdzie m, n , nazywamy prostokątną tablicę złożoną z m$\times$n liczb rzeczywistych ustawionych w m wierszach i n kolumnach
Suma/różnica
Niech macierz , . Sumą/różnicą nazywamy macierz , której elementy określone są wzorami
Zatem,
Iloczyn macierzy przez liczbę
Niech niech będzie dowolną liczbą rzeczywistą. Iloczynem macierzy przez liczbę nazywamy macierz której elementy określone są następująco:
dla {}, {}. Piszemy wtedy
Zatem
Iloczyn macierzy
Iloczyn macierzy jest możliwy jeśli macierz ma tyle samo kolumn co macierz ma wierszy. Iloczynem macierzy przez macierz nazywamy macierz taką, że:
Własności iloczynu macierzy:
Macierz transponowana
Niech
Wówczas
Rząd macierzy
Chcąc obliczyć rząd macierzy musimy znależć największą macierz, której wyznacznik jest różny od zera, wielkość tej niezerowej macierzy będzie szukaną wartością, czyli jeśli największą macierzą, której wyznacznik jest różny od zera jest macierz to rząd macierzy jest równy .
Przyklad
Aby obliczyć rząd macierzy zaczynamy od obliczenia wyznacznika największej macierzy czyli w tym przypadku
Następnie obliczamy macierze do momentu aż wyjdzie nam liczba różna od zera. Z macierzy można utowrzyć 16 macierzy w następujący sposób:
Jeżeli któraś z nich wyjdzie różna od zera to koniec obliczeń. Wystarczy że obliczając wyznacznik macierzy pierwszej wyjdzie nam liczba różna od zera - wtedy z automatu możemy powiedzieć, że rząd macierzy wynosi . Analogicznie jeżeli wszystkie wzory wyjdą na , to wtedy szukamy macierzy poprzez wykreślenie wiersza i kolumny analogicznie jak do kroków powyżej tak aby otrzymać macierz (czyli wykreślając po dwa wiersze i dwie kolumny).
Dla macierzy
operacja ta wygalda nastepująco:
Wyznacznik macierzy
np. Metoda Sarrusa
np. Rozwinięcie Laplace'a
Szukamy w macierzy wiersza lub kolumny która ma najwięcej zer (dla łatwiejszego obliczania). Na przykład:
Dla macierzy
Sytuacja wyglada tak:
Gdzie po równaniu pierwsza liczba to liczba wiersza i kolumny pomnożone przez do potegi razy macierz po wykreśleniu wiersza i kolumny . Następne dodajemy analogicznie.
Maceirz odwrotna $(A^{-1})$
Wzór:
gdzie:
Nie można obliczyć macierzy odwrotnej z macierzy osobliwej, czyli takiej której wyznacznik jest równy . Więc jeśli liczymy macierz odwrotną zawsze zaczynamy od obliczania wyznacznika macierzy, jeśli wyjdzie on to znaczy, że z danej macierzy nie można obliczyć macierzy odwrotnej.
Macierz odwrotna jest określona tylko dla macierzy kwadratowych, których wyznacznik jest .
Macierz odwrotna do macierzy kwadratowej to macierz spełniająca równanie , gdzie to macierz jednostkowa.
Jeśli macierz istnieje to macierz nazwyamy odwracalną, a jeśli macierz nie istnieje to macierz nazywamy nieodwracalną.
Jeśli macierz jest odwracalna to istnieje tylko jedna macierz odwrotna
Własności macierzy odwrotnej
Macierz nieosobliwa - macierz kwadratowa o wyznaczniku róznym od zera
Macierz symetryczna - macierz kwadratowa której wyrazy położone symetrycznie względem przekątnej głównej są równe, przykład:
Proces obliczania macierzy odwrotnej dla macierzy $3\times 3$
Podobnie jak wcześniej najpierw obliczamy wyznacznik macierzy :
Następnie obliczamy macierz dopełnień algebraicznych:
czyli
Więc:
Następnie obliczamy macierz transponowaną:
więc macierz odwrotna będzie miała postać:
Ślad macierzy
Ślad macierzy jest to suma elementów leżących na przekątnej danej macierzy. Ślad macierzy definujemy tylko dla macierzy kwadratowej. Ślad macierzy kwadratowej stopnia jest sumą elementów leżących na głównej przekątnej (diagonali). Ślad macierzy oznaczamy lub .
Mając macierz
obliczamy ślad macierzy w następujący sposób:
Własności śladu macierzy
Rozważmy układ równań liniowych o niewiadomych :
oraz macierz :
nazywać będziemy macierzą układu .
Macierz
nazywać będziemy macierzą wynikową.
Macierz
nazywać będzimy macierzą rozszerzoną układu .
Rozwiązaniem układu nazywać będziemy każdy -elementowy ciąg taki, że po podstawieniu do układu otrzymujemy równości:
Operacje elementarne
Za pomocą operacji elementarnych możemy przekształcać wiersze macierzy.
Możliwe operacje elementarne:
Metoda eliminacji Gaussa
Metoda eliminacji Gaussa polega na stosowaniu operacji elementarnych do macierzy rozszerzonej uładu równań liniowych tak, aby doprowadzić macierz rozszerzoną do postaci schodkowej.
Postać schodkowa:
Przykład:
Twierdzenie Cramera
Rozważamy układ równań liniowych o niewiadomych :
Jeżeli wyznacznik macierzy tego układu jest różny od zero to ten układ ma dokładnie jedno rozwiązanie postaci:
Natomiast macierz powstaje z macierzy poprzez zastąpienie -tej kolumny macierzy przez kolumnę macierzy wynikowej.
Przykład
Najpierw sprawdźmy czy wyznacznik macierzy układu jest rózny od zera
Oznacza to e układ ten ma dokladnie jedno rozwiązanie.
Musimy znalezc wzynacznik odpowiadajace kolejnym niewiadomym, czyli .
$A_1$
Wykreslamy pierwsza kolumne macierzy
W wolne miejsce wpisujemy kolumne macierzy wynikowej
Obliczamy wartosc
Teraz mozemy wyznaczyc niewiadoma
$A_2$
$A_3$
Podsumowujac otrzymalismy nastepujace rzowiazanie ukldau rownan:
Wniosek z twierdzenia Cramera
Prawem rachunku zdan lub tautologia nazywamy wyrażenie zbudowane ze zdań prostych i spójników, które zawsze jest zdaniem prawdziwym (niezależnie od wartości logicznych zdań prostych).
TAUTOLOGIA
W logice wartość logiczną zdania definiujemy jako 0, gdy zdanie to jest
fałszywe, zaś jako 1 , gdy zdanie to jest prawdziwe.
Symbolu 0 używamy również do oznaczenia dowolnego zdania fałszywego,
zaś symbolu 1 do oznaczenia dowolnego zdania prawdziwego.
Koniunkcja - to dwa zdania połączone spójnikiem logicznym .
Koniunkcja dwóch zdań jest prawdziwa jedynie wtedy, gdy oba zdania oraz są prawdziwe.
Alternatywa - to dwa zdania połączone spójnikiem logicznym .
Alternatywa dwóch zdań jest prawdziwa wtedy, gdy przynajmniej jedno ze zdań lub jest prawdziwe.
Implikacja - możemy odczytywać na wiele równoważnych sposobów:
Rownowaznosc - możemy odczytywać na wiele równoważnych sposobów:
Negacja - oznacza jednoargumentowy spójnik negacji, oznacza zdanie:
Najwazniejsze tautologie
Tautologia (z greki) - to wyrażenie, zdanie logiczne, które zawsze jest logiczne
Indukcja matematyczna – metoda dowodzenia twierdzeń o prawdziwości nieskończonej liczby stwierdzeń oraz definiowania rekurencyjnego. W najbardziej typowych przypadkach dotyczą one liczb naturalnych.
Aksjomat indukcji matematycznej
Jeśli jest podzbiorem , ktory spelnia:
to stanowi calosc , tzn .
Innymi slowy oznacza to ze jezeli dowiedziemy ze dany zbior posiada takie same wlasciwosci jak zbior (tj. jest dyskretny, posiada poczatkowy element oraz odlegosc miedzy nasepnymi dyskretnymi elementami jest zawsze taka sama) to element ten jest podzbiorem ale np przesunietym i powiekszonym o jakis skalar.
Przyklady

Permutacja zbioru -elementowego - to dowolny -wyrazowy ciąg utworzony ze wszystkich elementów tego zbioru.
Liczbę permutacji zbioru -elementowego możemy obliczyć ze wzoru:
Przyklady
Kombinacja pozwala policzyć na ile sposobów można wybrać elementów z -elementowego zbioru.
Wzór na kombinację jest następujący:
Kombinację zapisujemy krótko za pomocą Symbolu Newtona:
Przyklady
Przyjmijmy, że mamy dany zbiór elementów (np. zbiór liter). Wariacja z powtórzeniami pozwala na utworzenie ciągu z elementów tego zbioru, z tym, że dopuszcza powtarzanie elementów.
Wzór na wariację z powtórzeniami jest następujący:
Przyklady
Przykładami taki słów są: .
Na każde z miejsc możemy wybrać jedną z liter, zatem wszystkich możliwości mamy:
Przykładami taki słów są: .
Na każde z miejsc możemy wybrać jedną z liter, zatem wszystkich możliwości mamy:
Przyjmijmy, że mamy dany zbiór elementów (np. zbiór liter). Wariacja bez powtórzeń pozwala na utworzenie ciągu z elementów tego zbioru, z tym, że nie dopuszcza powtarzania elementów. Wzór na wariację bez powtórzeń jest następujący:
Przyklady
Mamy do dyspozycji cyfr: .
Przykładowymi kodami o różnych cyfrach są: . Wszystkich takich wariacji bez powtórzeń jest:
Definicja
Zakładamy, że przestrzeń zdarzeń elementarnych \OmegaΩ ma skończoną liczbę zdarzeń elementarnych i każde z nich jest jednakowo prawdopodobne. Wtedy prawdopodobieństwo definiujemy następująco:
Dla dowolnego
Kilka wyjaśnień:
Krótko: prawdopodobieństwo uzyskania jakiegoś wyniku to liczba sprzyjających wyników przez liczbę wszystkich możliwych wyników. Zatem chcąc obliczyć prawdopodobieństwo zajścia pewnego zdarzenia:
Własności prawdopodobieństwa
Prawdopodobieństwo dowolnego zdarzenia losowego A jest zawsze liczbą z przedziału ⟨0;1⟩.
Prawdopodobieństwo zdarzenia pewnego jest równe 1.
Prawdopodobieństwo zdarzenia niemożliwego jest równe 0.
Przydatne wzory
Prawdopodobieństwo zdarzenia przeciwnego:
Prawdopodobieństwo sumy zdarzeń
Prawdopodobieństwo warunkowe
Prawdopodobieństwo warunkowe zajścia zdarzenia A pod warunkiem zajścia zdarzenia B liczymy ze wzoru:
Prawdopodobieństwo całkowite
Jeżeli zdarzenia są parami rozłączne oraz mają prawdopodobieństwa dodatnie, które sumują się do jedynki, to dla dowolnego zdarzenia A zachodzi wzór:
Wzór Bayesa
Jeżeli zdarzenia są parami rozłączne oraz mają prawdopodobieństwa dodatnie, które sumują się do jedynki, to dla dowolnego zdarzenia A zachodzi wzór:
Schemat Bernoulliego
W schemacie Bernoulliego prawdopodobieństwo uzyskania k sukcesów w n próbach można obliczyć ze wzoru:
Klasyczny komputer o architekturze podanej przez von Neumana składa się z trzech podstawowych bloków:
Struktura logiczna komputera
Po załadowaniu programu do pamięci komputera może on zostać w dowolnej chwili wywołany przez operatora. W tym celu musi on wydać polecenie rozpoczęcia wykonywania tego programu przez wymuszenie odczytania pierwszego polecenia tego programu. W tym celu należy spowodować, aby procesor wysłał do pamięci odpowiedni adres. Dalsze polecenia są umieszczone w pamięci kolejno, więc będą odczytywane przez procesor automatycznie. Wykonywanie programu polega, więc na pobieraniu z pamięci kolejnych poleceń i odpowiednich dla tych poleceń argumentów. Argumenty rozkazu mogą być:
- w pamięci i wówczas rozkaz musi zawierać adres miejsca w pamięci, gdzie one się znajduje,
- w rejestrach procesora i wówczas rozkaz musi wskazywać adres odpowiedniego rejestru,
- w samym rozkazie i wówczas programista umieszcza je w odpowiednio w kodzie programu.
W czasie wykonywania programu procesor odczytuje kolejne rozkazy, które następnie musi rozpoznać (dekodować). Po zdekodowaniu rozkazu, w zależności od treści tego rozkazu, procesor podejmuje odpowiednią akcję. Akcja ta polega na wykonaniu odpowiedniej operacji. Między innymi, z treści rozkazu, może wynikać konieczność odczytania argumentów dla niego.
Jeżeli argument znajduje się, w pamięci, to dalsza akcja polega na odczytaniu adresu tego argumentu. Jeżeli adres ten programista umieścił w kodzie programu, to odczytane będzie następne słowo(a) z kodu programu stanowiące ten adres. Jeżeli argument znajduje sic, w rejestrze procesora, to rozkaz musi wskazać, w którym z rejestrów procesora znajduje się adres. Po skompletowaniu całej instrukcji procesor wykonuje ją, a dalej pobiera następny rozkaz i cała akcja się powtarza.

(schemat czytamy od gory - strzalka znika z prawej strony i pojawia sei po lewej dolnej stronie)
Na schemacie:
Typowa organizacja procesora to blok rejestrów, blok ALU i dekoder kodu rozkazowego. Najważniejszym układem procesora jest blok arytmetyczno logiczny ALU wykonujący operacje na argumentach z dwóch rejestrów A i B. Cykl pracy procesora rozpoczyna się od wysłania do pamięci adresu rozkazu. Adres ten znajduje się, w rejestrze LR zwanym licznikiem rozkazów.
Odczytywany z pamięci rozkaz zostaje przesłany do rejestru rozkazów RR. Zawartość tego rejestru jest dekodowana i blok ALU zostaje odpowiednio wysterowany do wykonania danej operacji. Zarówno rozkazy procesora jak i argumenty tych rozkazów są przedstawiane w komputerze w postaci słów binarnych, tj. kodowane w zapisie dwójkowym. (dlugosc slowa zawsze jest taka sama i odpowiada bitowosci komputera tj. 8-bitow, 16-bitow, 32-bity itd)

Pamięć jest podzielona na komórki, w których są przechowywane pojedyncze słowa (bajty). Każda komórka ma swój adres i podanie tego adresu na wejście adresowe pamięci umożliwia dostęp do danej komórki, czyli odczyt lub zapis. W zależności od sygnału O (odczyt) / Z (zapis) pamięć jest odczytywana lub zapisywana.
Wielkość takiej pamięci nazywana jest pojemnością pamięci i jest oznaczana przez (liczba pamiętanych słów przez długość słowa). W jednym cyklu pracy takiej pamięci można odczytać lub zapisać tylko słowo 8-bitowe. W przypadku, gdy długość rozkazu lub argumentu jest większa, to jest on zapisywany w dwóch (lub więcej) komórkach pamięci. Cykl instrukcyjny składa się z 4 faz:
- fazy pobrania rozkazu
- dwóch faz pobrania argumentów rozkazu
- fazy zapisu wyniku do pamięci.
Pozycyjny system liczbowy - to system liczbowy ktory opiera sie o pewien skonczony zestaw cyfr tego systemu. Kazda liczba w systemie pozycyjnym zostaje przedstawiona jako ciag cyfr tego systemu gdzie kazda nastepna cyfra na indeksie () gdzie to ilosc cyfr tego systemu, przedstawia wartosc .
Wzor:
Przyklady
Zamiana z na $(10)$
Zamiana z na $(2), (16)$
Zamiana z na $(16)$

Zamiana z na $(2)$

Zastowosawnie systemu dwojkowego
System dwojkowy oznaczany wykorzystywany jest jako glowny podloze wszystkich obliczen komputerow elektronicznych. Zostal wybrany na system pozycyjny komputerow poniewaz moze przedstawiac brak napieca a napiecie na danej sciezce, w danej komorce pamieci lub nosniku danych co sprawia ze jest to system bardzo prosty poniewaz nie wymaga pomiaru poziomu napiecia pradu przeplywajacego przez komponent w celu uzyskania danyhc z tego komponentu.
Zastosowanie systemu szesnastkowego
System szesnastkowy oznaczany wykorzystywany jest jako roziwniecie systeu dowjkowego. Dzieki wiekszej podstawie tego systemu, liczby zapisywane w nim sa bardziej kompaktowe i dzieki temu bardziej czytelne.
Komputerowa reprezentacja liczb calkowitych z przedzialu od do (przedzial zalezy od standardu), gdzie n jest liczba bitów w slowie maszynowym, zapisywanych w kodzie uzupelnien do dwóch. Zakres liczb 16-bitowych w a.s. (komputery PC) miesci sie w przedziale . Przekroczenie zakresu liczb powoduje nadmiar. W arytmetyce stalopozycyjnej sa wykonywane cztery podstawowe dzialania (+, -, * i /), przy czym stosuje sie dzielenie calkowite.
Reprezentacja liczby rzeczywistej zapisanej za pomocą notacji naukowej. Ze względu na wygodę operowania na takich liczbach, przyjmuje się ograniczony zakres na mantysę i cechę – nazwy te mają w matematyce znaczenie podane w artykule podłoga i sufit, a w niniejszym artykule inne, powszechne w informatyce. Powoduje to, że reprezentacja liczby rzeczywistej jest tylko przybliżona, a jedna liczba zmiennoprzecinkowa może reprezentować różne liczby rzeczywiste z pewnego zakresu.
Stalopozycjne (calkowite)

Stalopozycjne (rzeczywiste)

Stalopozycjne (rzeczywiste cd.)

Zmiennopozycyjne

Źródło: wykład "Wprowadzenie do systemów operacyjnych"
System operacyjny jest warstwą oprogramowania operującą bezpośrednio na sprzęcie, której celem jest zarządzanie zasobami systemu komputerowego i stworzenie użytkownikowi środowiska łatwiejszego do zrozumienia i wykorzystania.

System operacyjny pośredniczy pomiędzy użytkownikiem a sprzętem, dostarczając wygodnego środowiska do wykonywania programów. Użytkownik końcowy korzysta z programów (aplikacji), na potrzeby których przydzielane są zasoby systemu komputerowego. Przydziałem tym zarządza system operacyjny, dzięki czemu można uzyskać stosunkowo duży stopień niezależności programów od konkretnego sprzętu oraz odpowiedni poziom bezpieczeństwa i sprawności działania.
Nie ma precyzyjnego określenia, które składniki wchodzą w skład systemu operacyjnego jako jego części.

W ogólnym przypadku w strukturze systemu operacyjnego wyróżnia się jądro oraz programy systemowe, które dostarczane są razem z systemem operacyjnym, ale nie stanowią integralnej części jądra. Jądro jest zbiorem modułów, które ukrywają szczegóły sprzętowej realizacji systemu komputerowego, udostępniając pewien zestaw usług, wykorzystywanych między innymi do implementacji programów systemowych.
Z punktu widzenia kontaktu z użytkownikiem istotny jest interpreter poleceń, który może być częścią jądra lub programem systemowym (np. w systemie UNIX). Interpreter wykonuje pewne polecenia wewnętrznie, tzn. moduł lub program interpretera dostarcza implementacji tych poleceń. Jeśli interpreter nie może wykonać wewnętrznie jakiegoś polecenia, uruchamia odpowiedni program (tzw. polecenie zewnętrzne), jako odrębny proces.
Programy systemowe (programy użytkowe systemu):
Zadania systemu operacyjnego:
Proces - uruchomiony program. Jeden program to może być wiele procesów, bo np. uruchomimy wiele razy ten jeden program. Każdy proces jest identyfikowany przez numer PID.
W systemie operacyjnym każdy proces posiada proces nadrzędny (rodzica), z kolei każdy proces może, poprzez wywołanie funkcji systemu operacyjnego, utworzyć swoje procesy potomne. W ten sposób tworzy się swego rodzaju drzewo procesów.
W skład procesu wchodzi:
W trakcie ładowania procesu do pamięci system operacyjny tworzy stos (stack) i stertę (heap).
Stos – do przechowywania zmiennych, parametrów funkcji, adresów powrotu. Sterta – do przechowywania dynamicznie alokowanych danych, np. listy
Stany procesu:
Czasami może być konieczne współbieżne wykonywanie pewnych fragmentów programu. Aby to zrealizować, program może zażądać utworzenia określonej liczby wątków, wykonujących wskazane części programu. Ta cecha systemu operacyjnego to wielowątkowość. W jednym procesie może być kilka wątków. Każdy wątek ma swój własny stos (posiada swoje zmienne lokalne)
Cecha systemu operacyjnego umożliwiająca równoczesne wykonywanie więcej niż jednego procesu (programu).
Jest jak policjant na skrzyżowaniu, który wskazuje, które auta mogą teraz przejechać przez skrzyżowanie. Jest to część systemu operacyjnego przełączająca procesy według polityki szeregowania zadań. Do jego zadań należy m.in. przełączanie kontekstu.
Planista krótkoterminowy ustala wartość priorytetu. Wybiera proces o najwyższym priorytecie do wykonania.

Możliwe jest zagłodzenie procesu, gdy dany proces nie jest w stanie zakończyć działania, ponieważ nie ma dostępu do procesora lub innego współdzielonego zasobu. Występuje najczęściej na skutek niewłaściwej pracy algorytmu szeregowania lub nadmiernego obciążenia systemu.
Zdarza się również tzw. zakleszczenie, czyli blokada wzajemna. Powstaje wtedy, gdy wiele zadań w tym samym czasie konkuruje o wyłączny dostęp do zasobów. Zakleszczenie:

Iteracja - czynność powtarzania (najczęściej wielokrotnego) tej samej instrukcji (albo wielu instrukcji) w pętli.
Rekurencja to w logice, programowaniu i w matematyce odwoływanie się np. funkcji lub definicji do samej siebie.
Najwięcej problemów związanych z rekurencją wiąże się z ograniczeniami stosu wywołań, a właściwie jego pojemności. Na stosie są odkładane kolejne wywołania danej metody i dopiero gdy dojdziemy do ostatniego elementu dane te są zbierane – bardzo łatwo więc o sytuację, gdy po prostu stos przepełnimy.
Silnia iteracyjnie: n! = 1 * 2 * 3...* n
Silnia rekurencyjnie: n! = n * (n-1)!
Ciąg Fibonacciego
Definicja: dla mamy
natomiast wyrazy 1 i 0 przyjmują wartość 1.
Fibonacci rekurencyjnie:
function FibR(n)
begin
if ( n=0 or n=1) then {
return 1
}
return FibR(n-1) + FibR(n-2)
end
Fibonacci iteracyjnie:
function FibI(n)
begin
tmp :=0 // zmienna tymczasowa (pomocnicza)
x := 1 // wyraz n-1
y := 1 // wyraz n-2
for i:=1 to n-1 step 1 {
tmp := y // zapamiętaj wyraz n-2
y := y+x // przesuń wyraz n-2 na kolejną wartość ci¡gu
x := tmp // przesuń wyraz n-1 na kolejną wartość ci¡gu
// czyli na warto±¢ wyrazu n-1 przed jego
// przesunięciem
}
return x
end
I mean..come on ;-;
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}
Note: The default keyword must be used as the last statement in the switch, and it does not need a break. default can be the first statement on the list, but it makes no sense since only this statement will be executed.
break and default keywords are optional.
Without a break statement, every statement from the matched case label to the end of the switch, including the default, is executed.
| Condition | Action |
|---|---|
| Converted value matches that of the promoted controlling expression. | Control is transferred to the statement following that label. |
| None of the constants match the constants in the case labels; a default label is present. | Control is transferred to the default label. |
| None of the constants match the constants in the case labels; no default label is present. | Control is transferred to the statement after the switch statement. |
Podprogramy – wydzielona część programu wykonująca określony zbiór instrukcji, posiadająca swoją nazwę i stanowiąca pewną odrębną całość. Ich nazwy powinny informować o ich wyniku działania.
Ogólnie przyjęta konwencja (w przypadku C++) typ_rezultatu nazwa_funkcji( lista parametrów formalnych); na przykład:
bool isPrime(int);
Podprogramy dzielą się na dwa rodzaje:
Innym szczególnym przypadkiem są metody – funkcje, które są własnością klasy lub obiektu. Bez ich istnienia nie można się do nich odwołać.
W niektórych językach programowania nie istnieje powyższy podział.
Jeżeli chodzi o C++, formalnie procedury nie istnieją, jednak łatwo się domyślić, że ustawiając jako typ rezultatu void możemy utworzyć coś na jej wzór.
Przekazywanie parametrów do podprogramów odbywa się głównie na dwa sposoby:
int addOne(int number) {
return number++; //przez wartość
}
int addOne(int &number) {
return number++; //przez referencję
}
Programowanie strukturalne – paradygmat programowania opierający się na podziale kodu źródłowego programu na procedury i hierarchicznie ułożone bloki z wykorzystaniem struktur kontrolnych w postaci instrukcji wyboru i pętli. Język programowania zgodny z paradygmatem programowania strukturalnego nazywa się językiem strukturalnym.
Struktury kontrolne:
Programowanie obiektowe – paradygmat programowania, w którym programy definiuje się za pomocą obiektów – elementów łączących stan i zachowanie. Obiektowy program komputerowy wyrażony jest jako zbiór takich obiektów, komunikujących się pomiędzy sobą w celu wykonywania zadań.
| Programowanie strukturalne |
|
|
| Programowanie obiektowe |
|
|
aka enkapsulacja
Polega na ukrywaniu informacji - ukrywanie pewnych danych składowych lub metod w obiektach danej klasy tak, aby były one dostępne tylko dla metod wewnętrznych danej klasy lub dla metod z klas z nią zaprzyjaźnionych.
Z pełną enkapsulacją mamy do czynienia wtedy gdy dostęp do wszystkich pól w klasie jest możliwy tylko i wyłącznie poprzez metody, lub inaczej: gdy wszystkie pola w klasie znajdują się w sekcji prywatnej (lub chronionej)
Klasa to definicja obiektu, zawierająca stan obiektu, określony wartościami pól, oraz możliwe zachowanie, określone dostępnymi metodami.
Obiekt to utworzony egzemplarz (instancja) określonej klasy, który posiada własny, indywidualny stan i zbiór zachowań.
Metoda to funkcja lub procedura, skojarzona z ogółem klasy lub poszczególnymi jej obiektami; określa możliwe zachowania
Pole (Właściwość) to zmienna dowolnego typu, skojarzona z ogółem klasy lub poszczególnymi jej obiektami; określa aktualny stan obiektu
Dziedziczenie to mechanizm definiowania nowej klasy na bazie już istniejącej, wzbogacając ją o nowe pola, metody lub zmieniając zakres ich widoczności.
Struct - wszystkie składowe (pola i metody) są domyślnie publiczne
Class - wszystkie składowe (pola i metody) są domyślnie prywatne
Metoda
class MyClass {
void privateMethod(); //deklaracja w klasie
public:
void publicMethod() { //definicja w klasie
//donothing;
};
}
Definicja klasy musi zawierać przynajmniej deklarację metody
Definicja metody, często dla czytelności kodu, jest umieszczana poza klasą
void MyClass::privateMethod() { //definicja poza klasą
//this method is depressed
}
struct Obj {
int a, b; //od C++11 możliwa inicjalizacja w klasie, np.
//int a = 0;
Obj(int _a = 0, int _b = 0){ //konstruktor
a = _a;
b = _b;
}
};
{
Obj x, y(1), z(1,2), v = 3, u = {3,4}; //wywołania konstruktora
Obj t[5], *s = new Obj, *p = new Obj[3]; //wielokrotne
}
Konstruktor domyślny:
struct Obj {
int a, b;
Obj(){ //konstruktor domyślny
a = 0;
b = 0;
}
Obj()=default;//konstruktor domyślny bez inicjalizacji(C++11)
};
{
Obj x, t[5]; //wywołania konstruktora domyślnego
Obj *s = new Obj, *p = new Obj[3]; //tu też
}
struct Obj {
int a, b;
Obj(int _a, int _b = 0){ //1- lub 2-parametrowy konstruktor
a = _a;
b = _b;
}
};
{
Obj y(1), z(1, 2); //wywołania konstruktora
Obj x; //brak konstruktora domyślnego – błąd kompilacji!
}
Konstruktor kopiujący:
struct Obj {
int a, b;
... //inne konstruktory łącznie z domyślnym
Obj(const Obj &o){ //konstruktor kopiujący
a = o.a;
b = o.b;
}
};
{
Obj x;
Obj y(x), z = x; //wywołania konstruktora kopiującego
}
struct Obj {
int a, b;
... //konstruktory łącznie z domyślnym
~Obj(){...} //destruktor
~Obj()=default; //destruktor domyślny (C++11)
};
{
Obj x, *p = new Obj; //wywołania konstruktora
delete p; //jawne wywołanie destruktora (obiekt *p)
} //niejawne wywołanie destruktora (obiekt x)
Destruktory obiektów:
{
Obj x, *p = new Obj, z;
{ Obj y; } //destruktor dla obiektu y
delete p; //destruktor dla obiektu *p
} //destruktor dla obiektu z i dalej dla x
Kiedy wywoływany jest destruktor?
Dla każdej klasy kompilator tworzy automatycznie (o ile nie zdefiniowano ich jawnie) następujące metody:
struct Obj {
int a, b;
};
{
Obj x; //konstruktor domyślny, atrybuty są przypadkowe
Obj y = x; //konstruktor kopiujący
x = y; //operator przypisania
} //destruktor domyślny obiektów y i x
W programowaniu obiektowym jest to obiekt pozwalający na sekwencyjny dostęp do wszystkich elementów lub części zawartych w innym obiekcie, zwykle kontenerze lub liście.
Podstawowym celem iteratora jest pozwolić użytkownikowi przetworzyć każdy element w kolekcji bez konieczności zagłębiania się w jej wewnętrzną strukturę. Np.: przejść do kolejnego elementu, na koniec na początek. Użytkownik nie musi np. zajmować się tym, że odwoła się do nieistniejącego elementu.
W C++ iteratory są szeroko wykorzystywane w bibliotece STL. Iteratory stosuje się zwykle w parach, gdzie jeden jest używany do właściwej iteracji, zaś drugi oznacza koniec kolekcji.
Iteratory tworzone są przez odpowiadający im kontener standardowymi metodami, takimi jak begin() i end(). Iterator zwrócony przez begin() wskazuje na pierwszy element, podczas gdy iteratorzwrócony przez end() wskazuje na pozycję za ostatnim elementem kontenera.
int main() {
vector<int> ar = { 1, 2, 3, 4, 5 };
// Declaring iterator to a vector
vector<int>::iterator ptr;
// Displaying vector elements using begin() and end()
cout << "The vector elements are : ";
for (ptr = ar.begin(); ptr < ar.end(); ptr++)
cout << *ptr << " ";
return 0;
}
Output:
The vector elements are : 1 2 3 4 5
Just in case: przeciążenie operatorów slajd 7+ (Cybula) oraz slajd 8+ (Wardowski).
Selektory
x.set(4, 4.5);
INSERT INTO TABLE osoby VALUES (’Jan’, ’Kowalski’);
SELECT imie FROM osoby WHERE nazwisko = ’Kowalski’;
UPDATE osoby SET imie = ’Adam’;
DELETE FROM osoby WHERE nazwisko = ’Kowalski’;
CREATE TABLE osoby (imie VARCHAR(50), nazwisko VARCHAR(50));
Jest to mechanizm umożliwiający tworzenie nowych klas na podstawie klasy już istniejących w ten sposób, że nowa klasa przejmuje (dziedziczy) wszystkie metody drugiej klasy.
Zalety:
Klasa oryginalna, na podstawie której tworzymy nową, nazywamy klasą macierzystą.
Klasa, która dziedziczy funkcjonalność innej klasy nazywamy klasą potomną.
class Pracownik {
private:
enum {ILE = 20};
char imie[ILE];
char nazwisko[ILE];
char stanowisko[ILE];
double pensja;
public:
Pracownik(const char*, const char*, const char*, double p);
void wypiszDane() const;
void ustawPensja(double);
double getPensja() const;
};
class Dyrektor : public Pracownik {
private:
double dodatekFunkcyjny;
public:
Dyrektor(double, const char* i, const char*, const char*, double p);
Dyrektor(double dF, const Pracownik &);
double getDodatekFunkcyjny() {return dodatekFunkcyjny;}
void setDodatekFunkcyjny(double dF) {dodatekFunkcyjny = dF;}
};
Dwukropek oznacza, że klasa Dyrektor powstała z klasy Pracownik, która tutaj stanowi publiczną klasę macierzystą (dziedziczenie publiczne). Obiekt klasy potomnej zawiera wszystkie pola składowe i metody klasy macierzystej. Gdy dziedziczenie jest publiczne, to wszystkie składowe publiczne klasy macierzystej stają się składowymi publicznymi klasy potomnej. Dostęp do odziedziczonych prywatnych składowych jest możliwy poprzez odziedziczone publiczne lub chronione metody klasy macierzystej.
Obiekt klasy potomnej
Obiekt klasy Dyrektor ma następujące cechy:
W klasie potomnej powinny być zdefiniowane własne konstruktory, które dostarczają danych
zarówno dla nowych pól jak i odziedziczonych.
Klasa potomna może być uzupełniona o dodatkowe pola składowe i metody.
Konstruktory klasy potomnej
Klasa potomna nie może korzystać z prywatnych składowych klasy macierzystej, musi więc odwoływać się do nich za pomocą publicznego interfejsu klasy macierzystej. W konsekwencji konstruktory klasy potomnej mogą wykorzystywać konstruktory klasy macierzystej.
Podczas tworzenia obiektu klasy potomnej tworzony jest najpierw obiekt klasy macierzystej. Aby wywołać odpowiedni konstruktor klasy macierzystej, wykorzystuje się tzw. listę inicjatorów konstruktora (listę inicjalizacyjną).
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p) : Pracownik (i,n, s, p) {
dodatekFunkcyjny = dF;
}
//konstruktor bez listy inicjalizacyjne
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p = 0) {
dodatekFunkcyjny = dF;
}
//powyższy konstruktor jest równoważny poniższemu:
Dyrektor::Dyrektor(double dF, const char* i, const char* n, const char* s, double p) : Pracownik() {
dodatekFunkcyjny = dF;
}
//konstruktor powodujący wywołanie konstruktora kopiującego:
Dyrektor::Dyrektor(double dF, const Pracownik & p) : Pracownik(p) {
dodatekFunkcyjny = dF;
}
Podczas likwidacji obiektu klasy potomnej w pierwszej kolejności wywoływany jest destruktor tej klasy, a następnie wywoływany jest destruktor klasy macierzystej.
Dyrektor anna(500,”Anna”, ”Lis”, ”Dyrektor”, 3000);
anna.wypiszDane();
Pracownik* p1;
p1 = &anna;
p1->wypiszDane();
Pracownik& p2 = anna;
p2.wypiszDane();
p1->setDodatekFunkcyjny(500); //błąd!!!, p1 wskazuje na obiekt klasy macierzystej
Pracownik p3();
Dyrektor& d1 = p3; //błąd!!!
Dyrektor* d2 = &p3; //błąd!!!
Inicjalizacja obiektu klasy macierzystej za pomocą obiektu klasy potomnej
Dyrektor dyr(300, ”Jan”, ”Kowalski”, ”Dyrektor”, 3000);
Pracownik p(dyr);
W powyższej sytuacji działa konstruktor kopiujący klasy macierzystej:
Pracownik(const Pracownik&);
Przypisanie obiektu klasy potomnej do obiektu klasy macierzystej
Dyrektor dyr(300, ”Jan”, ”Kowalski”, ”Dyrektor”, 3000);
Pracownik p;
p = dyr;
W powyższej sytuacji działa w sposób niejawny operator przypisania:
Pracownik& operator=(const Pracownik&);
W C++ wyróżniamy trzy rodzaje dziedziczenia:
Dziedziczenie - kontrola dostępu:

MyAbstractClass abclass; //błąd!
MyAbstractClass * p; //OK
Dziedziczenie wielokrotne zazwyczaj prowadzi do niejednoznaczności wywołań funkcji.
Najlepszym rozwiązaniem jest przedefiniowanie wszystkich metod w klasie, która dziedziczy z
wielu klas macierzystych. W przedefiniowanych metodach przeważnie wskazujemy w sposób
jawny, które wersje metod chcemy wywołać.
Mechanizm polegający na tym, że jedna metoda może występować w wielu różnych postaciach w zależności od kontekstu jej wywołania nazywamy polimorfizmem.
W celu wdrożenia polimorficznego działania dziedziczenia publicznego stosujemy:
Aby odpowiednia wersja metody została wywołana należy przed deklaracją metody umieścić słowo virtual. W definicji słowo virtual pomijamy.
virtual double getPensja(); //deklaracja metody dla klasy Dyrektor
...
double getPensja() { //definicja metody
return Pracownik::getPensja() + dodatekFunkcyjny;
}
W przypadku poprzedzenia deklaracji słowem virtual, odpowiednia wersja metody zostanie wywołana w oparciu o typ obiektu, do którego odwołuje się referencja lub wskaźnik.
Dyrektor anna;
Pracownik janek;
Pracownik& p1 = anna;
Pracownik& p2 = janek;
p1.getPensja(); //wywołana metoda Dyrektor::getPensja();
p2.getPensja(); //wywołana metoda Pracownik::getPensja();
W przypadku, gdy metoda przedefiniowana nie jest poprzedzona w części deklaracyjnej słowem virtual, wówczas sposób działania metody opiera się na typie referencji, a nie na typie obiektu.
Dyrektor anna;
Pracownik janek;
Pracownik& p1 = anna;
Pracownik& p2 = janek;
p1.getPensja(); //wywołana metoda Pracownik::getPensja();
p2.getPensja(); //wywołana metoda Pracownik::getPensja();
Zazwyczaj dobrą praktyką jest poprzedzanie w klasie macierzystej słowem virtual deklaracje tych metod, które są przedefiniowane w klasie potomnej. Zabieg ten pozwala wybrać odpowiednie wersje metod, na podstawie obiektu, na rzecz którego są one wywoływane, a nie na postawie referencji lub wskaźnika.
Poprzedzenie destruktorów słowem virtual powoduje, że podczas destrukcji obiektu zostanie wywołany odpowiedni kod destruktora.
Wiązanie nazwy funkcji polega na określeniu odpowiedniego bloku wykonywalnego (w kodzie skompilowanym), który ma zostać użyty.
Wiązanie statyczne to wiązanie, które jest realizowane podczas kompilacji kodu źródłowego.
Wiązanie dynamiczne, to odpowiedni mechanizm, który pozwala wybrać odpowiednią metodę wirtualną podczas działania programu.
Uwaga Wiązanie dynamiczne zachodzi wówczas, gdy odpowiednie metody wywoływane są przez wskaźniki lub referencje.
Polimorfizm statyczny jest często implementowany za pomocą szablonów. Jest on nieograniczony, bo interfejsy typów uczestniczących w polimorfizmie nie są z góry określone.
Szablony służą do tworzenia ogólnych deklaracji klas (lub funkcji). W ten sposób realizowana jest koncepcja tzw. typów sparametryzowanych. Typ jest argumentem przekazywanym do ogólnego wzorca klasy lub funkcji.
Szablony pozwalają na wielokrotne wykorzystanie istniejącego kodu źródłowego struktury danych dla wielu wersji tej struktury z tym samym interfejsem, ale różnymi typami dla wewnętrznych komponentów (programowanie generyczne/uogólnione, struktury parametryzowane)
template <typename T>
class Punkt {
private:
T x, y;
public:
Punkt();
Punkt(T,T);
T getX();
T getY();
void setXY(T,T);
void wypisz();
};
template <typename T>
Punkt<T>::Punkt() {
x = y = 0;
}
template <typename T>
T Punkt<T>::getX() {
return x;
}
...
Chcąc wygenerować klasę na podstawie zdefiniowanego szablonu należy jawnie określić typ parametru (tzn. dokonać jawnej konkretyzacji typu).
#include <iostream>
#include "Punkttp.h"
using namespace std;
int main() {
Punkt<int> p(3,2);
cout << p.getX();
Punkt<double> z(3.2,2.1);
z.setXY(5.01,3);
return 0;
}
Konkretyzując klasę możemy użyć zarówno typu wbudowanego jak i obiektu jakiejś klasy.
W języku C++ możemy używać szablony, które posiadają więcej niż jeden argument typu. Korzystając z tej możliwości możemy utworzyć klasę do przechowywania dwóch elementów różnych typów.
template <typename T1, typename T2>
class Pair {
private: T1 x, T2 y;
public:
T1 & first(const T1 & f) {x = f; return x;};
T2 & second(const T2 & s) {y = s; return y;};
T1 first() const {return x;}
T2 second() const {return y;}
Pair(const T1 & f, const T2 & s) : x(f), y(s) {}
Pair(){}
};
Listy
Lista to ciąg elementów, gdzie każdy zawiera atrybuty: key, next oraz previous. Wartość każdego z tych elementów odczytujemy przez key[x]. Listy reprezentujemy poprzez obiekt, zawierający atrybuty head oraz tail, wskazujące odpowiednio na początek i koniec listy.
Listy dzielimy na 3 typy:
W liście jednokierunkowej każdy z elementów wskazuje na element następny, czyli dla każdego x, next[x] wskazuje na kolejny. Ostatni element listy wskazuje na pusty element NIL.

W liście dwukierunkowej każdy element zawiera trzy atrybuty. Oprócz atrybutu next zawiera także previous wskazujący na poprzedni element listy. Na pusty element NIL wskazuje zarówno pierwszy jak i ostatni element listy.

Listą cykliczną nazywamy listę, w której ostatni element zamiast wskazywać na pusty element NIL, wskazuje na pierwszy element listy. Nie występują tutaj atrybuty head i tail.

Stos
Stos to liniowa struktura danych, gdzie elementy przetwarzane są w kolejności od tego, który pojawił się najpóźniej (jest na górze stosu) do tego, który pojawił się na samym początku (na dole stosu).
Poszczególne elementy można przeglądać, lecz by pobrać element znajdujący się poniżej, trzeba pobrać ze stosu wszystkie elementy znajdujące się nad nim.
W algorytmach stos reprezentowany jest przez strukturę LIFO (Last In First Out).
Kolejka
Kolejka jest strukturą działającą przeciwnie do stosu. Dane są przetwarzane w kolejności ich pojawienia się, tzn.: zaczynając od tego, który pojawił się na początku, kończąc na tym, który znalazł się na samym końcu.
W algorytmach kolejka reprezentowana jest poprzez strukturę FIFO (First In First Out).
Drzewa
Drzewo składa się z elementów , które posiadają trzy atrybuty: key, left oraz right.
Drzewo reprezentowane jest przez obiekt z atrybutem root (korzeń). Kolejne elementy są jego potomkami.

W informatyce drzewo wykorzystywane jest do budowy drzew decyzyjnych, które są podstawą działania takich algorytmów jak min-max (wyznaczanie optymalnych ruchów).
Grafy
Graf To struktura matematyczna służąca do przedstawiania i badania relacji między obiektami. W uproszczeniu Graf to zbiór wierzchołków, które mogą być połączone krawędziami w taki sposób, że każda krawędź kończy się i zaczyna w którymś z wierzchołków.
Grafem nieskierowanym nazywamy parę G=(V, E), gdzie V jest pewnym zbiorem skończonym zwanym zbiorem wierzchołków grafu G.
Natomiast E jest zbiorem nieuporządkowanych par {u, v} gdzie u, v V oraz u != v.
Zbiór E nazywamy zbiorem krawędzi grafu G.

Jeśli {u, v} jest krawędzią grafu nieskierowanego G, to mówimy, że {u, v} jest incydentna z wierzchołkami u i v.
Stopniem wierzchołka w grafie nieskierowanym nazywamy liczbę incydentnych z nim krawędzi. Pętlę liczymy za 2.
Grafem skierowanym nazywamy parę G=(V, E), gdzie V jest pewnym zbiorem skończonym zwanym zbiorem wierzchołków grafu G.
Natomiast E - zbiór krawędzi grafu G.
G - zbiór uporządkowanych par *{u, v} oznaczanych (u, v), gdzie u, v V

Stopniem wierzchołka w grafie skierowanym nazywamy sumę liczby krawędzi wchodzących do wierzchołka i wychodzących z tego wierzchołka
Rząd grafu - liczba wierzchołków w grafie.
Rozmiar grafu - liczba krawędzi w grafie.
Droga (ścieżka) - drogą w grafie będziemy nazywać ciąg krawędzi taki, że koniec jednej stanowi początek następnej. Drogę nazywamy prostą, gdy wszystkie jej wierzchołki są różne.
Osiągalność - mówimy, że v jest osiągalny z u, gdy istnieje droga z u do v.
Cykl - cyklem nazywamy zamkniętą drogę x1x2x3...xnx1 w grafie skierowanym, gdzie to wierzchołki x1x2...xn to wierzchołki drogi, która jest długości co najmniej 1. Gdy wszystkie wierzchołki są różne to cykl nazywamy prostym. Cykl o długości 1 nazywamy pętlą.
Mówimy, że ścieżka <v0, v1, ..., vk> tworzy cykl w grafie nieskierowanym, gdy v0 = vk, v1 ... vk są różne oraz k >=2
Graf niezawierający cykli nazywamy grafem acyklicznym.
Acykliczny graf nieskierowany nazywamy lasem.
Graf prosty to graf bez krawędzi wielokrotnych i bez pętli.
Graf regularny to fraf, w którym wszystkie wierzchołki są tego samego stopnia.
Graf pusty to graf, w którym w ogólne nie ma krawędzi (są same wierzchołki izolowane).
Graf pełny to graf prosty, w którym każdy wierzchołek jest połączony krawędzią z każdym.
Graf jest spójny, gdy każda para różnych wierzchołków jest połaczona drogą w tym grafie.
Spójny podgraf grafu G, który nie jest zawarty w żadnym większym spójnym podgrafie tego grafu, nazywamy składową grafu G.
Spójny, acykliczny graf nieskierowany nazywamy drzewem (wolnym).
Cykl Eulera - droga zamknięta przechodząca przez każdą krawędź grafu dokładnie raz.
Droga Eulera - droga przechodząca przez każdą krawędź grafu dokładnie raz.
Graf, który posiada cykl Eulera Musi mieć wszystkie wierzchołki stopnia parzystego.
Graf, który posiada drogę Eulera ma albo dokładnie dwa wierzchołki stopnia nieparzystego, albo nie ma w ogóle takich wierzchołków.
Graf spójny, mający dokładnie 2 wierzchołki stopnia nieparzystego posiada drogę Eulera.
Formy reprezentacji grafów
Macierz sąsiedztwa
Macierzą sąsiedztwa grafu (skierowanego lub nie) nazywamy macierz M o wymiarze VxV, w której wartości reprezentują wagę połączeń pomiędzy wierzchołkami, 1 gdy połączone, 0 gdy nie ma.

Lista sąsiedztwa
Dane zapisywane są w postaci listy obiektów zawierających wierzchołek grafu, wraz z listą wierzchołków sąsiednich. W przypadku grafu nieskierowanego listy są dłuższe, ponieważ muszą odzwierciedlać krawędzie w obu kierunkach.

Macierz incydencji
Macierz incydencji jest macierzą A o wymiarze n x m, gdzie n oznacza liczbę wierzchołków grafu, natomiast m liczbę jego krawędzi. Każdy wiersz tej macierzy odwzorowuje jeden wierzchołek grafu. Każda kolumna odwzorowuje jedną krawędź. Zawartość komurki A[i, j] określa powiązanie (incydencję) wierzchołka vi z krawędzią ej w sposób następujący:

Jeśli graf jest nieskierowany, to definicję macierzy należy uprościć:

Zastosowania
Mapy - Aby znaleźć najkrótszą drogę by dostać się z jednego miejsca do drugiego można wykorzystać graf, którego wierzchołki będą odpowiadały miejscowością a krawędzie drogom.
Dokumenty hipertekstowe - Przeszukując internet napotykamy dokumenty, które zawierają odnośniki do innych dokumentów - internet jest grafem, którego wierzchołkami sa dokumenty a krawędziami odsyłacze.
Sieci - Sieć komputerowa zbudowana jest z komputerów, które przesyłają między sobą informacje. Komputery w danej sieci reprezentowane są przez wierzchołki grafu, a połączenia między nimi krawędziami.
Struktura programu - Kompilator buduje graf reprezentujący strukturę wywołań podprogramów w kompilowanym programie. Wierzchołkami grafu są różne funkcje, natomiast krawędzie są kojarzone z wywołaniem funkcji./
Dziel i rządź
Polega na rekurencyjnym dzieleniu problemu na mniejsze podproblemy. Dzielenie trwa dopóni nie uzyskamy problemów, które da się w prosty sposób rozwiązać.
Algorytmy wykorzystujące metodę "dziel i rządź":
Programowanie dynamiczne
Jest stosowane głównie do rozwiązywania problemów optymalizacyjnych. Jest alternatywą dla niektórych zagadnień rozwiązywanych metodami zachłannymi. Wyniki poszczególnych obliczeń są zapamiętywane w pomocniczej tablicy, która jest wykorzystywana w kolejnych krokach. Eliminuje to konieczność wielokrotnego powtarzania tych samych obliczeń.
Algorytmy wykorzystujące programowanie dynamiczne:
Algorytm zachłanny
W każdym kroku dokonuje wyboru będącego na daną chwilę tym najlepszym. Podejmuje decyzje optymalne tylko lokalnie. Kontynuuje działania wynikające z poprzednich decyzji.
Algorytmy wykorzystujące metodę zachłanną:
Elementarne metody sortowania:
Sortowanie przez selekcję (selection sort) - Jego czas działania jest określany z góry O(n2). Sortowanie to jest najlepsze, spośród innych elementarnych do sortowania elementów o małych kluczach i dużych polach, ponieważ wykonuje najmniej wstawień. W pierwszym przebiegu algorytm znajduje najmniejszy element w tablicy i zamienia go z pierwszym. W drugim algorytm znajduje najmniejszy element w podtablicy i zamienia go z drugim. Tak aż do zamiany r-tego elementu z r-1 elementem.
Sortowanie bąbelkowe - Czas działania jest z góry określony przez O(n2) - algorytm wykonuje w najgorszym i średnim przypadku podobną ilość porównań i zamian. Zadada działania opiera się na cyklicznym porównywaniu par sąsiadujących elementów i zamianie ich kolejności w przypadku niespełniania kryterium porządkowego zbioru. Operację tę wykonujemy dotąd, aż cały zbiór zostanie posortowany.
Nieelementarne metody sortowania:
Quicksort (sortowanie szybkie) - Średnia złożoność obliczeniowa O(n log n)Bazuje na strategii dziel i rządź. Problem dzielimy rekurencyjnie na podproblemy a następnie łączymy w jedno rozwiązanie. Z tablicy wybiera się element rozdzielający, po czym tablica jest dzielona na dwa fragmenty: do początkowego przenoszone są wszystkie elementy nie większe od rozdzielającego, do końcowego wszystkie większe. Potem sortuje się osobno początkową i końcową część tablicy. Rekurencję kończy się, gdy kolejny fragment uzyskany z podziału zawiera pojedynczy element, jako że jednoelementowa tablica nie wymaga sortowania.
Sortowanie pozycyjne - Algorytm porządkujący stabilnie ciągi wartości (liczb, słów) względem konkretnych cyfr, znaków itp, kolejno od najmniej znaczących do najbardziej znaczących pozycji. Złożoność obliczeniowa jest równa O(d(n+k)), gdzie k to liczba różnych cyfr, a d liczba cyfr w kluczach. Wymaga O(n+k) dodatkowej pamięci.
Wyszukiwanie liniowe/sekwencyjne
Wyszukiwanie binarne
Wyszukiwanie max lub min
Naiwne wyszukiwanie wzorca w tekście
Algorytm ustawia okno o długości wzorca p na pierwszej pozycji w łańcuchu s a następnie sprawdza czy zawartość wzorca p i porównywanego fragmentu łańcucha s są sobie równe
W przypadku pozytywnym pozycja okna jest zwracana jako wynik
Po porównaniu okno przesuwa się o jedną pozycje w prawo i cała procedura powtarza się, dopóki okno nie wyjdzie poza koniec łańcucha s
Posiada złożoność obliczeniową równą O(n x m) pesymistycznie, oraz o(n) w najlepszym przypadku.
n - długość łańcucha
m - długość wzorca
Haszowanie
Unikanie kolizji
Haszowanie - zastosowania
Haszowanie - wady
Mierzymy liczbę operacji wykonanych na modelu. Następnie próbujemy znaleźć funkcję, która będzie opisywała liczbę operacji w zależności od wejścia algorytmu. Funkcje te możemy porównać ze sobą.

Ile mamy tu operacji? Przypisanie, pętla for. Jej ciało zawiera jedną operację. Sama pętla wykona się dokładnie tyle razy ule jest elementów tablicy numbers. Liczbę tych elementów określimy jako n. Na końcu mamy instrukcję return sum.
Dodając do siebie otrzymujemy wzór:
Zatem złożoność naszego algotyrmu opisana jest przez funkcję f(n) = n+2. Tak więc wyznacza się ją poprostu licząc operacje.
Jak oszacować rząd złożoności funkcji?
Wyobraźmy sobie pewien algorytm. Funkcja, która go opisuje to np.: f(n) = n3 - 6n2 + 4n + 12
Argument n to rozmiar danych wejściowych do algorytmu. Wykres tej funkcji wygląda następująco:

Notacja Dużego O zakłada, że istnieje funkcja g(n), dla której spełniona jest poniższa wartość:
n n0 : f(n) c g(n)
Oznacza to, że wynik funkcji g(n) pomnożony przez jakąś stałą c, będzie większy bądź równy wynikowi funkcji f(n). Własność ta jest spełniona dla wszystkich n, które będą większe od n0. Jeszcze łatwiej wygląda to na wykresie:

Pokazuje on dwie funkcje. Pierwszą z poprzedniego wykresu. Druga to wykres funkcji g(n) = n3. Od pewnego punktu zielona linia jest zawsze ponad czerwoną linią. To nic innego jak oszacowanie z góry. To właśnie robi notacja O. Zatem w naszym przypadku nasza funkcja f(n) ma złożoność O(n3)
Baza danych jest zbiorem danych oraz narzędzi Zystemu Zarządzania Bazą Danych (SZBD) przeznaczonego do zarządzania nią oraz gromadzenia, przekształcania i wyszukiwania danych.
To zbiór usystematyzowanych informacji (danych), który dotyczy rzeczywistości a konkretnie określonego jej fragmentu (wycinka), który reprezentuje. Fragment ten określamy mianem obszaru analizy.
Cechy bazy danych
System zarządzania bazą danych (SZBD) obsługuje użytkowników bazy danych, umożliwiając im eklploatację oraz tworzenie baz danych. By stworzyć i zaprojektować bazę danych, nalezy ją zidentyfikować, a do tego konieczne jest określenie typów przechowywanych w niej danych. Istotną rolę odgrywa również wyznaczenie użytkowników oraz ich praw dostępu.
Właściwości bazy danych (funkcje SZBD)
Podział baz danych
Postulaty Codda
Elementy relacyjnej bazy danych
KONIEC SLAJD 186!!!
Rodzaje powiązań w relacyjnej bazie danych
Klucz główny
Dość często spotykanym problemem na etapie projektowania bazy danych jest określenie, która kolumna (kolumny) będzie pełnić funkcję klucza głównego. Ponieważ każdy wiersz w tabel musi my jednoznacznie zidentyfikować , zachodzi potrzeba wybrania atrybutów (kolumn), które spełniają to zadanie. Klucz główny odgrywa bardzo ważną rolę w tabeli (relacji), dlatego jego wybór powinien zostać poprzedzony analizą typowanych przez nas kolumn pod kątem wymienionych poniżej własności:
Aby jednoznacznie zidentyfikować wiersz tabeli, stosuje się atrybut (kolumnę), której poszczególne wartości dla kolejnych krotek (wierszy) będą niepowtarzalne
Atrybut będący kluczem głównym możemy stworzyć sztucznie dla przykładu wprowadzając kolejne numerowanie wierszy 1, 2, 3, 4, 5 itd., pod warunkiem że każdy wiersz ma inny numer. Możemy również posłużyć się określoną cechą (atrybutem) opisywanej rzeczywistości (encji), np. dokonując spisu ludności, możemy posłużyć się numerem PESEL. Ponieważ każdy człowiek ma inny niepowtarzalny numer PESEL, nie zachodzi obawa, że może on się powtórzyć. Taką kolumnę (atrybut) nazywamy kluczem Głównym (primary key).
Rodzake kluczy
Kluczem może być zatem jedna lub kilka kolumn, które wspólnie będą w stanie jednoznacznie zidentyfikować pozostałe dane w tabeli (relacji). Kolumny, które należą do kluczy (używa się ich do jednoznacznej identyfikacji wierszy w tabeli), nazywamy atrybutami podstawowymi. Kolumny nie należące do kluczy (zawierają dane, które w określonej relacji są przedmiotem opisu) nazywamy atrybutami opisowymi.
Do łączenia dwóch tabel (np. A i B) za pomocą związków używa się klucza. Klucz pochodzący z obcej tabeli B (w której jest on kluczem głównym), używany do łączenia tej tabeli z tabelą A, będzie dla tabeli A kluczem obcym.
Superklucz (superkey) – to kolumna lub zestaw kolumn jednoznacznie identyfikujących każda krotkę tabeli. Super klucz może zawierać kolumny, które samodzielnie mogą nie identyfikować każdej z krotek. Unikatowa identyfikacja każdej z krotek może odbywać się jedynie przez zestaw np. dwóch lub trzech atrybutów. Przedmiotem zainteresowań projektantów baz danych jest taki superklucz, który zawiera minimalny zestaw atrybutów unikatowo identyfikujących krotkę.
Klucz kandydujący (nadklucz, klucz potencjalny) o super klucz zawierający minimalną liczbę kolumn unikatowo identyfikujących krotki relacji. W praktyce to kolumna lub kolumny, których użycie w charakterze klucza głównego jest rozważane przez projektanta baz danych. To właśnie twórca bazy danych decyduje, której kolumnie (kolumnom) nada funkcję klucza głównego.
Klucz główny (primary key) to klucz, który został wybrany, aby unikatowo identyfikować krotki
tabeli. Klucz główny jest podyktowany wyborem projektanta bazy danych.
h
Spójność referencyjna baz danych polega na wprowadzeniu i utrzymaniu powiązań pomiędzy tabelami.
To zespół reguł, które gwarantują logiczną spójność danych wprowadzanych i przechowywanych w bazie. Zadaniem więzów spójności jest zagwarantowanie tego, aby dane w bazie danych wiernie odzwierciedlały świat rzeczywisty, dla opisu którego baza danych została zaprojektowana. Więzy spójności definiowane są na etapie projektowania bazy danych, tworzone wraz z innymi obiektami, przy tworzeniu bazy.
Wyróżniamy dwa typy więzów spójności:
Spójność encji - ograniczają możliwe wartości, jakie mogą się pojawić w wierszu tabeli:
Spójność referencyjna - zapewniają, że zbiór wartości w kolumnach klucza obcego jest zawsze podzbiorem zbioru wartości odpowiadającego mu klucza głównego lub jednoznacznego. Ponieważ wartości klucza głównego lub jednoznacznego jednoznacznie określają obiekty, więc klucz obcy wskazuje zawsze na istniejący obiekt. Wartością klucza obcego może też być NULL – wówczas klucz obcy nie wskazuje na żaden obiekt. System zapewnia, aby obiekt wskazywany przez wartość klucza obcego zawsze istniał, niezależnie od wszystkich możliwych operacji na tabelach, w których biorą udział klucze główne, jednoznaczne i obce.
Normalizacja baz danych - proces w ramach którego doprowadzamy bazę danych do postaci normalnych. W przypadku gdy baza danych nie jest znormalizowana występuje redundancja danych.
Redundancja danych w najprostszym wytłumaczeniem jest sytuacją gdy dane się powtarzają np. są zdublowane.
Pierwsza postać normalna - występuje gdy każda kolumna jest atomowa tzn. nie zawiera list i dane są niepodzielne.

Przedstawiona tabela nie spełnia pierwszej postaci normalnej (1NF) ponieważ kolumna Adres nie jest atomowa. Możemy ją podzielić na pojedyncze kolumny. Aby więc doprowadzić naszą tabelę do 1NF należy kolumnę adres podzielić na kilka pojedynczych kolumn. Poniższa tabela została tak zmieniona, że spełnia 1NF:

Druga postać normalna - baza danych jest w drugiej postaci normalnej gdy spełnia pierwszą postać normalną oraz wszystkie kolumny w tabeli zależą tylko od klucza.
Czy powyższa baza jest w 2NF? Nie ponieważ jak się zastanowić to z tabeli możemy wyodrębnić przynajmniej trzy zbiory danych zależne od różnych kluczy: KLIENT, PIZZA, ZAMÓWIENIE.

Powyższa baza została sprowadzona do drugiej postaci normalnej.
Trzecia postać normalna - Baza jest w trzeciej postaci normalnej wtedy gdy spełnia drugą postać normalną oraz żadna z kolumn nie jest zależna od innej kolumny która nie jest kluczem.
Tabela KLIENT spełnia 3NF natomiast tabela PIZZA jej nie spełnia ponieważ kolumna CENA nie jest zależna od klucza a od wielkośc i pizzy. Aby to zmienić należy dane dotyczące cen wyciągnąć do inny tabeli jak na poniższym schemacie:

Kolejne postacie normalne W bazach danych występują jeszcze inne postaci normalne jak: Byce-Codde, 4NF, 5NF. Kolejne postaci normalne mówią, że naszą bazę można jeszcze bardziej podzielić. Dla przykładu miasto nie jest bezpośrednio związane z adresem a z ulicą na którą zamawiamy dlatego też ulicę można by wyciągnąć do osobnej tabeli.
Klucz potencjalny - minimalny zestaw atrybutów relacji, jednoznacznie identyfikujący każdą krotkę tej relacji. W relacji może znajdować się wiele kluczy potencjalnych (zwanych czasem kandydującymi). Spośród kluczy potencjalnych wybiera się zazwyczaj jeden klucz, zwany kluczem głównym.
Klucz główny (primary key) – wybrany minimalny zestaw atrybutów relacji, jednoznacznie identyfikujący każdy rekord
tej relacji. To oznacza, że taki klucz musi przyjmować wyłącznie wartości niepowtarzalne i nie może być wartością
pustą (null). Ponadto każda relacja może mieć najwyżej jeden klucz główny.
Kluczem głównym może być dowolny klucz potencjalny, ale często stosuje się rozwiązanie polegające na utworzeniu
specjalnego atrybutu, którego wartości domyślne pobierane są z sekwencji (tzw. autonumeracja), tak aby zapewnić
unikalność klucza.
Klucz obcy - kombinacja jednego lub wielu atrybutów tabeli, które wyrażają się w dwóch lub większej liczbie relacji (tabel). Wykorzystuje się go do tworzenia powiązania pomiędzy parą tabel, gdzie w jednej tabeli ten zbiór atrybutów jest kluczem obcym, a w drugiej kluczem głównym.



Indeksowanie jest podstawowym mechanizmem wykorzystywanym w celu optymalizacji baz danych SQL. Gdyby porównać bazę danych do książki, indeksy są czymś w rodzaju spisu treści.
Z technicznego punktu widzenia (i mocno uogólniając) indeksy to zbiór wartości typu „klucz – lokalizacja”. Dzięki temu, na podstawie konkretnego klucza czyli parametrów zapytania jest możliwe bardzo szybkie zwrócenie odpowiednich danych.
Klucze w indeksie przechowywane są w strukturze zwanej B-Tree (nie należy mylić tej struktury danych z drzewem binarnym). B-Tree pozwala mechanizmom SQL Server znaleźć pożądany rekord szybciej i wydajniej, ale tylko wtedy, gdy wyszukiwanie w tym drzewie odbywa się za pomocą klucza.
B-drzewo i Drzewo binarne to typy nieliniowej struktury danych. Chociaż warunki wydają się być podobne, ale różnią się pod każdym względem.
Drzewo binarne jest używane, gdy rekordy lub dane są przechowywane w pamięci RAM zamiast na dysku, ponieważ prędkość dostępu do pamięci RAM jest znacznie większa niż na dysku. Z drugiej strony B-tree jest używane, gdy dane są przechowywane na dysku, skraca czas dostępu, zmniejszając wysokość drzewa i zwiększając gałęzie w węźle.

Problem z przeszukiwaniem baz danych polega na tym, że tabele nie są posortowane. Jedyna „kolejność” to często klucz
główny PRIMARY_KEY. Nie jest to przydatna kolejność kiedy szukamy danych nie po kluczu a po jakimś innym polu np: SELECT nazwa_produktu FROM produkty WHERE cena = 128;
W przypadku kiedy dane są posortowane po kluczu głównym trzeba „sprawdzić” wszystkie rekordy i nie mamy możliwości ułatwienia sobie zadania bo produkty mogą mieć przecież różną cenę. Mówi wtedy że dokonujemy pełnego skanu tabeli, który działa niekorzystnie na wydajność. Indeksowania polega na unikaniu tego pełnego skanu.
Indeks jest uporządkowanym plikiem rekordów indeksu o stałej długości. Rekordy indeksu zawierają dwa pola: klucz reprezentujący jedną z wartości występujących w atrybutach indeksowych relacji oraz wskaźnik do bloku danych zawierający krotkę, której atrybut indeksowy równy jest kluczowi.
Korzyść wydajnościowa ze stosowania indeksów jest największa w przypadku dużych tabel (zawierających najwięcej rekordów) oraz zapytań, które wykonywane są najczęściej.
W MySQL zaleca się indeksować następujące kolumny: -kolumny najczęściej padające po słowie WHERE,
Należy pamiętać, że indeks drastycznie spowalnia dodawanie, modyfikowanie i usuwanie danych, ponieważ indeksy muszą być aktualizowane za każdym razem, gdy tabela ulega nawet najmniejszej modyfikacji. Najlepszą praktyką jest dodanie indeksu dla wartości, które są często używane do wyszukiwania, ale nie ulegają częstym zmianom.
W jednej tabeli możemy posiadać tylko jeden index klastrowany dla jednej lub wielu kolumn. Założenie takiego indexu równa się fizycznemu posortowaniu danych na dysku, w związku z tym niemożliwe jest założenie dwóch tego rodzaju indexów.
Odczyt danych z tabeli która nie jest jest posortowana w przypadku gdy posiada setki tysięcy bądź miliony rekordów jest bardzo czasochłonne. Serwer bazodanowy musi przejść rekord po rekordzie, by zwrócić dane o które prosimy. W związku z tym należy założyć index, na przynajmniej jedną kolumnę aby usprawnić proces ‚poszukiwania’ rekordów.
CREATE CLUSTERED INDEX nazwaIndeksu ON nazwaTabeli(nazwaKolumny);
Index klastrowany może być tylko jeden, ale może zostać założony na więcej niż jedną kolumnę
CREATE CLUSTERED INDEX IX_EmployeesAgeFullName ON Employees(Age,FullName);
Nasza tabela została posortowana najpierw po kolumnie Age a następnie po kolumnie FullName
Są swego rodzaju kopią danych, kopią kolumny na którą został założony taki index. Możemy posiadać więcej niż jeden index non-clustred, jednak warto wiedzieć, że podczas zapisu danych do tabeli, jeśli dane wymagają ponownego posortowania, to operacja zapisu będzię trwać dłużej. Im więcej indexów, tym dłuższy czas oczekiwania na ukończenie operacji. Tego typu index jest również wolniejszy jeżeli odpytujemy o więcej danych, niż zostało to zadeklarowane na początku.
CREATE NONCLUSTERED INDEX nazwaIndexu ON nazwaTablicy(nazwaKolumny);
Do manipulowania tabelkami używa się kilku poleceń:
Polecenia CREATE TABLE i ALTER TABLE są ponadto używane w celu definiowania ograniczeń kluczy oraz tzw. parametrów przechowywania, które są rozszerzeniami składni Oracle.
Tworzenie nowej tabeli CREATE TABLE nazwa_tabeli (nazwa_kolumny1 typ_danych1);
nr_towar NUMBER(4),
nazwa VARCHAR2(15),
cena NUMBER(7,2),
kategoria VARCHAR2(30),
stan_magazyn NUMBER,
wycofany CHAR(3) );
CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15),
cena NUMBER(7,2),
kategoria VARCHAR2(30),
stan_magazyn NUMBER,
wycofany CHAR(3) );
Tabele i ich zawartość są usuwane za pomocą polecenia DROP TABLE nazwa_tabeli. Dla tabel, do których nie odwołuje się żaden klucz obcy, tabela i jej zawartość zostanie całkowicie usunięta.
Przykład: DROP TABLE czytelnicy CASCADE CONSTRAINTS;
Przykład: TRUNCATE TABLE towary;
Z pewnymi ograniczeniami, przy użyciu opcji MODIFY polecenia ALTER TABLE można zmienić cztery części definicji kolumny:
Przykład: ALTER TABLE towary MODIFY (kategoria VARCHAR(30) NOT NULL);
Usunięcie kolumny z tabeli:
Przykład: ALTER TABLE nazwa_tabeli DROP COLUMN nazwa_kolumny;
Ograniczenia, jakie można ustawić dla tabel/kolumn służą następującym celom:
Ograniczenia mogą być:
Istnieje kilka możliwości wykorzystania ograniczenia CHECK:
Ograniczenie CHECK jest definiowane:
Przykład:
CREATE TABLE drużyny_pilkarskie (
nr_druzyny NUMBER(4) NOT NULL,
nazwa VARCHAR2(30) NOT NULL,
liczba_goli NUMBER NOT NULL,
liczba_goli_dom NUMBER CHECK(liczba_goli_dom <= liczba_goli), liczba_goli_wyjazd
NUMBER CHECK(liczba_goli_wyjazd <= liczba_goli) );
Nazywanie ograniczeń Jeśli w tabeli wprowadzamy ograniczenia bez podawania ich nazw, wówczas system sam nadaje każdemu ograniczeniu unikalną nazwę, która jest przechowywana w przestrzeni nazw.
Dla przykładu utwórzmy tabelę towary nazywając ograniczenia:
CREATE TABLE towary (
nr_towar NUMBER(4),
nazwa VARCHAR2(15) CONSTRAINT nazwa_nn NOT NULL,
cena NUMBER(7,2) CONSTRAINT cena_nn NOT NULL,
kategoria VARCHAR2(30) CONSTRAINT kategoria_nn NOT NULL, stan_magazyn
NUMBER DEFAULT 0,
wycofany CHAR(3) DEFAULT ‘Nie’,
CONSTRAINT towary_pk PRIMARY KEY(nr_towar),
CONSTRAINT wycofany_CH CHECK(wycofany IN ('Tak', 'Nie')));
W języku SQL poleceniami służącymi do modyfikowania danych w tabelach są jedynie trzy operacje, które zaliczamy do operacji DML:
Za pomocą polecenia INSERT można:
Składnia:
Przykład:
INSERT INTO towary (nr_towar, nazwa, cena, nazwa_kategorii, stan magazynu) VALUES (104, 'chleb', 2.20, 'pieczywo',100);
Składnia DELETE:
DELETE FROM nazwa_tabeli WHERE warunek_logiczny;
Przykład:
DELETE FROM towarywycofane
WHERE nr_towar IN (SELECT nr_towar
FROM towary WHERE stan = 0);
Polecenie TRUNCATE TABLE nazwa_tabeli przyśpiesza proces usuwania dzięki temu, że nie zapisuje informacji sprzed modyfikacji do przestrzeni wycofania. Ten fakt powoduje jednak, iż nie jest możliwe przywrócenie usuniętych danych. To polecenie nie zawiera także klauzuli WHERE, a zatem zawsze usuwa wszystkie wiersze wskazanej tabeli.
Polecenie UPDATE dotyczące aktualizacji danych różni się od pozostałych dwóch operacji DML dotyczących modyfikacji danych w tabelach, ponieważ nie ma wpływu na liczbę wierszy w tabeli.
Składnia:
UPDATE nazwa_tabeli
SET lista
WHERE warunek;
gdzie:
Polecenie UPDATE - przykład
UPDATE towary SET nazwa = ‘czekolada mleczna’, cena = 2.50 WHERE nr_towar = 1;
Podstawową, najczęściej używaną instrukcją języka SQL jest instrukcja SELECT, która służy do pobierania danych z jednej tabeli lub większej liczby tabel (widoków). Niezależnie od liczby tabel i/lub widoków oraz niezależnie od rodzaju operacji wykonywanych na zbiorach lub pseudozbiorach, zawsze jako wynik otrzymujemy wirtualną pojedynczą tabelę (tzw. dynamiczny zestaw wyników), którą dalej możemy przetwarzać.
Składnia:
SELECT lista_kolumn FROM lista_tabel;
Pobranie wszystkich wierszy i wszystkich kolumn:
SELECT * FROM towary;
Pobieranie wszystkich wierszy i wybranych kolumn:
SELECT nazwa, cena FROM towary;
W języku SQL listy przecinkowe są wykorzystywane w różnych celach:
Istotna odmiana listy przecinkowej powstaje w wyniku tzw. aliasingu, czyli nadawania aliasów („pseudonimów”) dla tych elementów, które bezpośrednio poprzedzają alias. Jeśli alias jest umieszczony za określanym elementem, to do tego elementu można odwołać się zarówno poprzez jego nazwę lub alias (poza pewnymi przypadkami, kiedy można odwołać się tylko za pomocą nazwy oraz pewnymi przypadkami, kiedy można odwołać się tylko za pomocą aliasu).
Przykład (nadanie zastępczych aliasów dwóm wyświetlanym kolumnom):
SELECT nazwa nazwa_towaru, cena cena_jednostkowa
FROM towary;
Klauzula ORDER BY instrukcji SELECT służy do sortowania danych w języku SQL. Sortowanie danych można wykonać na dwa sposoby: albo w porządku rosnącym (ustawienie domyślne) – opcja ASC lub w porządku malejącym wartości kolumny użytej do sortowania – opcja DESC.
Przykład:
SELECT nr_towar, nazwa, cena, stan, towary
FROM towary
ORDER BY cena DESC;
Zanim dane z urządzenia źródłowego zostaną przesłane do urządzenia końcowego muszą przejść długą drogę, podczas której najpierw są odpowiednio oznaczane, tagowane, opisywane określonymi informacjami pozwalającymi na ich identyfikację, potem przesyłane są pomiędzy wieloma urządzeniami pośredniczącymi, aż trafią do odbiorcy, który dane to potem musi zinterpretować.
Gdyby nie istniał taki model, który dzieli komunikację na mniejsze, łatwiejsze do zrozumienia i zarządzania etapy oraz określa zadania, jakie muszą być realizowane w poszczególnych warstwach trudno byłoby we właściwy sposób zarządzać komunikacją sieciową ponieważ mnogość rozwiązań i technologii powodowałaby olbrzymi chaos, trudny do opanowania.
Warstwa 7: aplikacji - Udostępnia użytkownikom możliwość korzystania z usług sieciowych, takich jak WWW, poczta elektroniczna, wymiana plików, połączenia terminalowe czy komunikatory.
Warstwa 6: prezentacji - Przekazuje do warstwy aplikacji informacje o zastosowanym formacie danych, np. informuje jakie typy plików będą przesyłane, odpowiada ona również za odpowiednie zakodowanie danych na urządzeniu źródłowym i ich dekodowanie na urządzeniu docelowym.
Warstwa 5: sesji - Warstwa sesji otrzymuje od różnych aplikacji dane, które muszą zostać odpowiednio zsynchronizowane. Synchronizacja występuje między warstwami sesji systemu nadawcy i odbiorcy. Warstwa sesji „wie”, która aplikacja łączy się z którą, dzięki czemu może zapewnić właściwy kierunek przepływu danych –nadzoruje połączenie. Wznawia je po przerwaniu.
Warstwa 4: transportu - Głównym zadaniem jest sprawna obsługa komunikacji pomiędzy urządzeniami. W warstwie tej dane dzielone są na mniejsze części, następnie opatrywane są dodatkowymi informacjami pozwalającymi zarówno przydzielić je do właściwej aplikacji na urządzeniu docelowym, jak i pozwalającymi złożyć je na urządzeniu docelowym w odpowiedniej kolejności.
Warstwa 3: sieci - Warstwa sieciowa jako jedyna dysponuje wiedzą dotyczącą fizycznej topologii sieci. Rozpoznaje, jakie drogi łączą poszczególne komputery (trasowanie) i decyduje, ile informacji należy przesłać jednym z połączeń, a ile innym. Jeżeli danych do przesłania jest zbyt wiele, to warstwa sieciowa po prostu je ignoruje.
Warstwa 2: łącza danych - Głównym zadaniem jest kontrola dostępu do medium transmisyjnego, a także adresowanie danych, tym razem jednak w celu przesyłania ich pomiędzy hostami w sieci LAN.
Warstwa 1: fizyczna - Koduje dane do postaci czystych bitów (zer i jedynek) i przesyła je poprzez medium transmisyjne do odpowiednich urządzeń.


TCP/IP (ang. Transmission Control Protocol/Internet Protocol) to zbiór protokołów służących do transmisji danych przez sieci komputerowe. Model TCP/IP został stworzony w latach 70. XX wieku w DARPA, aby pomóc w tworzeniu odpornych na atak sieci komputerowych. Potem stał się podstawą struktury Internetu. Model TCP/IP implementuje najważniejsze funkcjonalności siedmiu warstw standardowego modelu OSI. Poniższy schemat przedstawia odpowiadające sobie warstwy modeli TCP/IP i OSI.

Każda wiadomość wysłana przez aplikację przechodzi przez wszystkie warstwy TCP/IP, od warstwy aplikacji do najniższej warstwy dostępu do sieci. Następnie jest transmitowana przez sieć do drugiego komputera. Na koniec przechodzi przez wszystkie warstwy w przeciwnym kierunku, aż do warstwy aplikacji i docelowego procesu. Podczas przesyłania danych z aplikacji do sieci, każda warstwa dodaje swój własny nagłówek do każdej wiadomości. Każdy z tych nagłówków jest potem odczytywany przez odpowiednią warstwę w komputerze odbierającym wiadomość. Zarówno zawartość jak i wielkość nagłówków zależą od użytych protokołów.


Pośredniczy w komunikacji pomiędzy programami komputerowymi i protokołami niższych warstw, umożliwiając w ten sposób aplikacjom korzystanie z sieci. Jest to warstwa najbliższa użytkownikowi, ponieważ to właśnie ona pozwala nam w pełni korzystać z usług sieciowych. Kiedy siadamy przed komputerem i uruchamiamy np. przeglądarkę internetową to korzystamy z sieci właśnie na poziomie warstwy aplikacji. Istnieje wiele protokołów warstwy aplikacji, które wykorzystują transmisję TCP/IP.
Budowa wiadomości warstwy aplikacji różni się w zależności od protokołu, który został użyty. Każdy protokół może wymagać różnych danych wejściowych i produkować różne zapytania, które będą wysłane do warstwy transportowej. Niezależnie od formy wiadomości utworzonej przez warstwę aplikacji, warstwa transportowa traktuje każdą otrzymaną wiadomość jako dane i nie wnika w ich zawartość.
Gniazda sieciowe to struktury, które są wykorzystywane podczas komunikacji pomiędzy warstwami aplikacji i transportową. Każdy proces i aplikacja, który próbuje połączyć się z siecią, musi powiązać swoje kanały transmisji danych wejściowych i wyjściowych poprzez utworzenie właściwego obiektu gniazda sieciowego.
Obiekt gniazda sieciowego zawiera informacje o adresie IP, numerze portu i użytym protokole warstwy transportowej. Unikalna kombinacja tych trzech parametrów pozwala na zidentyfikowanie właściwego procesu, do którego wiadomość powinna być dostarczona.
Numer portu może zostać przypisany automatycznie przez system operacyjny, ręcznie przez użytkownika lub może być mu przypisana wartość domyślna, właściwa pewnym popularnym aplikacjom. Numer portu jest 16-bitową liczbą całkowitą (0 - 65535).
Niektóre popularne protokoły warstwy aplikacji używają domyślnych i publicznie znanych numerów porów. Na przykład, HTTP używa portu 80, HTTPS używa portu 443, SMTP portu 25, Telnet portu 23, natomiast FTP używa dwóch portów: 20 do transmisji danych i 21 kontroli transmisji. Lista domyślnych numerów portów jest zarządzana przez organizację Internet Assigned Numbers Authority.
Jej głównym zadaniem jest sprawna obsługa komunikacji pomiędzy urządzeniami. W warstwie tej dane dzielone są na mniejsze części, następnie opatrywane są dodatkowymi informacjami (nagłówki) pozwalającymi zarówno przydzielić je do właściwej aplikacji na urządzeniu docelowym, jak i pozwalającymi złożyć je na urządzeniu docelowym w odpowiedniej kolejności. Nagłówek zawiera szereg informacji kontrolnych, w szczególności numery portów nadawcy i odbiorcy.
Najpopularniejszym protokołem warstwy transportowej jest TCP (ang. Transmission Control Protocol). Podczas transmisji danych, TCP zestawia połączenie pomiędzy komunikującymi się stronami przez zainicjowanie tzw. sesji (ang. session). TCP jest protokołem niezawodnym, w którym odbiorca potwierdza otrzymanie każdej wiadomości. Wszystkie wiadomości dostarczane są w takiej samej kolejności, w jakiej zostały wysłane. Wszystkie cechy wymienione powyżej są zapewniane przez warstwę TCP. Oznacza to, że TCP może współdziałać z innymi, bardziej zawodnymi protokołami niższych warstw i nie powinno to afektować komunikacji z perspektywy warstwy aplikacji.
Odbiorca testuje każdy otrzymany pakiet pod kątem błędów transmisji (poprzez wyliczanie sumy kontrolnej danych). Jeśli wiadomość jest poprawna, odbiorca wysyła potwierdzenie do nadawcy. Jeśli nadawca nie otrzyma potwierdzenia w przeciągu określonego (konfigurowalnego) czasu, to ponownie wysyła zagubiony pakiet. Po kilku nieudanych próbach, TCP zakłada, że odbiorca jest nieosiągalny i informuje warstwę aplikacji, że transmisja zakończyła się niepowodzeniem.
Jedno z pól nagłówka TCP zawiera numer sekwencyjny wiadomości. Numer sekwencyjny jest zwiększany o jeden dla każdej wysłanej wiadomości. Podczas odbierania wiadomości, TCP układa pakiety we właściwej kolejności. Dzięki temu, warstwa aplikacji nie musi w ogóle zajmować się kolejnością przychodzących pakietów sieciowych.
Składa się z 20 lub więcej bajtów. Dokładna wielkość zależy od tego czy opcjonalne pole opcji jest używane. Maksymalna wielkość tego pola to 40 bajtów, więc maksymalna wielkość całego nagłówka to 60 bajtów.

W celu wymiany danych przy pomocy TCP, dwie aplikacje muszą najpierw
zainicjować sesję.
TCP wymaga wymiany trzech wiadomości żeby utworzyć sesję:
Kiedy transmisja pomiędzy klientem i serwerem zostanie zakończona, sesja powinna zostać zamknięta. Każda strona komunikacji może zakończyć trwającą sesję. Druga strona powinna odpowiedzieć na to, wysyłając odpowiednie potwierdzenie.
Zastosowanie TCP. TCP jest szeroko wykorzystywane w protokołach i aplikacjach, które wymagają wysokiej niezawodności. Można wymienić wiele protokołów warstwy aplikacji, które używane są głównie razem z TCP.
Jednymi z najpopularniejszych są:
Drugim popularnym protokołem używanym w warstwie transportowej jest UDP (ang. User Datagram Protocol lub Universal Datagram Protocol). Jest to prostszy protokół, w którym komunikacja odbywa się bez nawiązywania żadnego stałego połączenia pomiędzy aplikacjami. Wszystkie pakiety wysyłane są niezależnie od siebie. Dzięki swojej prostocie UDP jest szybsze niż TCP. Z drugiej jednak strony, nie zapewnia takiej niezawodności działania jak TCP, nie gwarantuje, że wiadomości rzeczywiście dotarły do odbiorcy. UDP nie dostarcza pakietów w takiej samej kolejności, w jakiej zostały one wysłane. Ciężar uporządkowania otrzymywanych wiadomości i sprawdzenia czy nie nastąpiły błędy transmisji spoczywa na otrzymującej je aplikacji.
Składa się z 8 bajtów, jest więc znacznie krótszy niż odpowiadający mu nagłówek TCP.

UDP jest preferowane jeśli przesyłane pakiety danych są nieistotne lub komunikacja musi odbywać się z wyjątkowo dużą prędkością czyli np. podczas transmisji audio i video, gdzie utrata pewnej liczby pakietów nie jest bardzo uciążliwa dla odbiorcy. Istnieje wiele protokołów warstwy aplikacji, które używają UDP, na przykład:
Datagram Congestion Control Protocol jest protokołem, który umożliwia aplikacjom
kontrolowanie przepływu danych w celu zapobiegania przeciążeniom sieci i utrzymywania
stabilnych połączeń. DCCP nie zapewnia niezawodnej komunikacji z zachowaniem kolejności
wysyłanych pakietów.
DCCP jest wykorzystywany przez aplikacje, które operują na szybko zmieniających się
danych (dane audio i video, gry online, VoIP). W takich sytuacjach często preferuje się użycie
nowej porcji dostępnych danych, zamiast proszenia o retransmitowanie starego
uszkodzonego pakietu.
Resource Reservation Protocol umożliwia zdalne rezerwowanie zasobów przy użyciu sieci
komputerowych. Jest używany głównie przez routery i serwery w celu zapewnienia usług
o określonej jakości dla klientów.
RSVP jest w stanie rezerwować pasma transmisji dla komunikacji pomiędzy dwoma
komputerami oraz pomiędzy jednym serwerem i wieloma klientami. Wymiana wiadomości w
ramach RSVP jest inicjowana przez klienta (odbiorcę), który prosi router (serwer)
o zarezerwowanie zasobów.
Stream Control Transmission Protocol umożliwia przesyłanie wielu strumieni danych
spakowanych razem w pojedynczym strumieniu. Podobnie jak TCP, SCTP zapewnia
niezawodną transmisję z zachowaniem kolejności pakietów i zapobieganiem przeciążeniom,
dodatkowo rozbudowując jego funkcjonalności o umieszczanie pokrewnych strumieni danych
w tych samych wiadomościach.
Ogólnie rzecz biorąc SCTP, jest bardzo rozbudowanym protokołem zapewniającym
dobrą jakość komunikacji. Niestety, z racji braku wspierania tego protokołu przez
najpopularniejsze routery i systemy operacyjne, nie jest on popularny i szerzej używany.
Głównym zadaniem jest odnalezienie najkrótszej i najszybszej drogi do urządzenia docelowego przez sieć rozległą, podobnie jak robią to samochodowe GPS’y, ale także adresowanie danych z wykorzystaniem adresów logicznych (adresów IP). Adres IP jest unikalnym wirtualnym numerem, który umożliwia znajdowanie urządzenia w sieci. Istnieje kilka popularnych protokołów, które działają w warstwie internetowej. Najpopularniejszym i najważniejszym z nich jest IP (Internet Protocol), ale warto wymienić też
Inne protokoły warstwy internetowej:
IP służy do przesyłania pakietów danych przez sieć. Obecnie używane są dwie wersje tego protokołu, IPv4 i IPv6.
IP nie zapewnia żadnego systemu potwierdzania dostarczenia wiadomości, co oznacza, że nie jest niezawodnym protokołem. Obowiązek upewniania się, że wszystkie dane zostały dostarczone spoczywa na protokole TCP operującym w warstwie transportowej. Całe połączenie TCP/IP jest więc niezawodne.
Pakiety danych otrzymywane z warstwy transportowej są dzielone na mniejsze datagramy.
Każdy datagram zawiera nagłówek IP oraz bajty otrzymane z warstwy transportowej.
Maksymalna wielkość datagramu zależy od wersji IP: 216−1 bajtów dla IPv4 oraz 232−1
dla IPv6. Jeśli pakiet otrzymany z warstwy transportowej jest zbyt duży, zostanie podzielony
na kilka datagramów o odpowiedniej wielkości.
Zwykle dane dzielone są na mniejsze datagramy niż wynikałoby to z ograniczeń protokołu IP.
Jest to spowodowane ograniczonymi możliwościami fizycznymi sieci komputerowych. Na
przykład, maksymalna wielkość ethernetowych pakietów wynosi 1 500 bajtów, więc zwykle
datagramy tworzone w warstwie internetowej operującej na ethernecie będą nieco mniejsze
niż 1 500 bajtów (aby umożliwić niższym warstwom dodanie swoich nagłówków).
Maksymalna wielkość datagramu w sieci jest nazywana MTU (Maximum Transfer Unit).
IP umożliwia dzielenie datagramów na mniejsze datagramy, jeśli przechodzą one przez sieć z
mniejszą wartością MTU. Kiedy mniejsze datagramy docierają znowu do sieci o większej
wartości MTU, mogą zostać ponownie zebrane do większego pakietu. W nagłówku IP jest
specjalne pole pozwalające na przeprowadzanie takich operacji (nazywające się Fragment Offset).
Umożliwia przesłanie datagramów z warstwy internetowej, przez fizyczną sieć do drugiego
komputera, gdzie są one przesyłane przez odpowiadającą jej warstwę dostępu do sieci do
warstwy internetowej, a następnie poprzez pozostałe warstwy do docelowej aplikacji.
Obecnie, większość komputerów jest podłączona do sieci ethernetowych, które mogą być
zarówno przewodowe jak i bezprzewodowe. Wobec tego protokoły TCP/IP wyższych warstw
najczęściej są używane razem z zestawem protokołów ethernetowych.
Istnieją trzy warstwy ethernetowe. Pierwsze dwie, Logic Link Control (LLC) i Media Access Control (MAC), odpowiadają warstwie łącza danych w modelu OSI. Trzecia, najniższa warstwa to warstwa fizyczna, podobnie jak w modelu OSI.

Jej najważniejszym zadaniem jest przekazanie informacji do docelowej maszyny odnośnie tego jaki protokół powinien być użyty w warstwie transportowej. Umożliwia to poprawne odczytanie przychodzącej wiadomości przez odbiorcę. Warstwa LLC dopisuje informacje o protokole użytym w warstwie internetowej i o protokole, który powinien otrzymać wiadomość. Pozwala to warstwie LLC na docelowym komputerze poprawnie dostarczyć otrzymane datagramy. Zdefiniowana przez standard IEEE 802.2.
jest odpowiedzialna za tworzenie końcowej wiadomości ethernetowej, która będzie wysłana przez sieć komputerową. Podobnie jak inne warstwy, warstwa MAC tworzy swój własny nagłówek i dodaje go do wiadomości. Nagłówek zawiera adresy MAC nadawcy i odbiorcy, czyli fizyczne adresy dwóch komunikujących się maszyn. Jeśli docelowa maszyna znajduje się za routerem, w innej sieci, to pole adresu odbiorcy będzie miało wartość adresu
routera. Adres MAC odbiorcy będzie zmieniony na inny przez router, kiedy będzie on przetwarzał wiadomość. Warstwa MAC dodaje również 4 kontrolne bajty CRC, które mogą być wykorzystane do naprawienia uszkodzonej wiadomości. Warstwa MAC dla sieci przewodowych jest zdefiniowana przez standard IEEE 802.3. Sieci bezprzewodowe są zdefiniowane przez IEEE 802.11. Warstwa Fizyczna Warstwa fizyczna jest odpowiedzialna za przekształcanie wiadomości w (zależności od typu sieci) impulsy elektryczne lub fale elektromagnetyczne oraz za transmitowanie ich przez sieć fizyczna pomiędzy komunikującymi się maszynami. Jest zdefiniowana przez te same specyfikacje co warstwa MAC, IEEE 802.3 i IEEE 802.11.
![]()
Cechy:
Cechy:
![]()
Cechy:
Cykl życia oprogramowania - Okres czasu rozpoczynający się kiedy pojawił się pomysł na oprogramowanie
Testowanie Oprogramowania - Jest to proces związany z wytwarzaniem oprogramowania. Jest on jednym z procesów kontroli jakości oprogramowania.
Podstawowym standardem dla testowania oprogramowania jest IEEE 829-1998 (829 Standard for Software Test Documentation).
Rodzaje testów:
Testy Manualne Testy wykonywane ręcznie przez testera, który przechodzi przez interfejs użytkownika zgodnie z określoną sekwencją kroków:
Testy dopasowane do aktualnego zapotrzebowania/przeznaczenia
Testy automatyczne Testy automatyczne skutecznie przyspieszają proces tworzenia testów systemowych, ich wykonywanie oraz analize, a tym samym pozwalają na wcześniejsze wykrycie i weliminowanie błędów w aplikacjach.
UML - Unified Modeling Language jest to język modelowy używany między innymi w inżynierii oprogramowania jako standardowy sposób wizualizacji projektu systemu.
Do kreacji UML przyczyniła się potrzeba standaryzacji różnych systemów wizualizacji systemów
rozwiazywania problemów. Został zaproponowany przez Rational software w połowie lat 90-
tych.
W 1997 UML został zaimplementowany przez Object Management Group jako główny system
organizacji, co było punktem przełomowym w popularyzacji języka.
W 2005 UML zostało zaadoptowane do standardu ISO (International Operation of
Standardization) i od tamtego czasu przechodzi okresowe rewizje, w 2020 roku wprowadzono
specyfikacje wersji 2.5.1
UML to sposób wizualizacji architektury systemów za pomocą diagramu. UML składa się ze standardowych elementów, które mają na celu przyspieszenie pracy. Diagram posiada sposoby wizualizacji miedzy innymi:
UML nie narzuca żadnego systemu pracy, ani żadnego systemu projektowania
oprogramowania. Jest jednak narzędziem, która wspomaga projektowanie tych systemów.
W programowaniu, bardzo dobrze sprawdza się jako sposób wizualizacji jak ma działać
program opierający się na obiektach.
Są różne systemy i UML stara się zaproponować wizualizacje każdego z nich za pomocą
różnych elementów, wyspecjalizowanych lub nie. Idea natomiast jest taka sama.
Diagram składa się z zawsze z wizualizacji danego obiektu, oraz interakcji między nimi.
Z takich standardowych przykładów używania UML możemy wymienić reprezentację systemu
za pomocą bramek logicznych.
UML 2 posiada wiele typów diagramów, które można podzielić na 2 typy :


Zespół projektowy jest to jednostka organizacyjna, powołana na zasadzie specjalizacji przedmiotowej, realizująca projekt pod bezpośrednim nadzorem kierownika projektu.
Grupa metod wytwarzania oprogramowania opartego na programowaniu iteracyjno-przyrostowym. Najważniejszym założeniem metodyk zwinnych jest obserwacja, że wymagania odbiorcy (klienta) często ewoluują podczas trwania projektu. Pojęcie zwinnego programowania zostało zaproponowane w 2001 w Manifeście Programowania Zwinnego.
„(...) Bardziej cenimy:
Ludzi i interakcje od procesów i narzędzi Działające
oprogramowanie od szczegółowej
dokumentacji
Współpracę z klientem od negocjacji umów
Reagowanie na zmiany od realizacji założonego planu.
Oznacza to, że elementy wypisane po prawej są wartościowe, ale większą wartość mają dla nas te, które wypisano po lewej.”
Są to iteracyjne i przyrostowe ramy postępowania zgodne ze Scrum Guide. Zgodnie z definicją ze Scrum Guide’a w obręb Scruma wchodzą: Zespoły Scrumowe oraz związane z nimi role, wydarzenia, artefakty i reguły.
ROLE: DEWELOPERZY + PRODUCT OWNER + SCRUM MASTER = ZESPÓŁ SCRUMOWY Deweloperzy, czyli zespół składający się z 3 9 osób z np.testera, analityka, webdewelopera, programisty dowolnego języka. Odpowiadają za sposób wykonania zadań. W zespole wszyscy powinni być równi. Product Owner odpowiada za wybór zadań do wykonania. Product Owner to osoba reprezentująca klienta , ciało jednoosobowe, jedyne, które może zlecać zadania zespołowi, dlatego bardzo ważne jest wsparcie jego roli w organizacji. Scrum Master czuwa nad tym, aby przebieg prac był zgodny z zasadami Scruma i ustalonymi przez zespół. Osoba ta odpowiedzialna jest za usuwanie wszelkich przeszkód uniemożliwiających zespołowi wykonanie zadania.
WYDARZENIA:
PLANOWANIE SPRINTU
CODZIENNY SCRUM +
PRZEGLĄD SPRINTU +
RETROSPEKTYWA =
SPRINT
ARTEFAKTY: BACKLOG PRODUKTU + BACKLOG SPRINTU + PRZYROST
Backlog Produktu to uporządkowana lista wszystkich rodzajów zadań potrzebnych do rozwoju, utrzymania i naprawy produktu.
Lista ta jest otwarta dla wszystkich w organizacji, natomiast Product Owner ma ostateczne słowo co do treści, wyglądu i
zawartości Backlogu. To jest jego narzędzie pracy nad produktem.
Backlog Sprintu to analogiczne narzędzie, ale dla Zespołu Deweloperskiego, który dzięki temu artefaktowi w pełni panuje nad
pracami zaplanowanymi na Sprint.
Przyrost to ukończona przez Zespół zgodnie z Definicją Ukończenia praca na koniec każdego i wszystkich razem Sprintów.
REGUŁY: PRZEJRZYSTOŚĆ + INSPEKCJA + ADAPTACJA
Przejrzystość zapewnia Zespowi Scrumowemu i wszystkim w organizacji dostęp do całości prac i takie samo rozumienie
każdego elementu Scruma. Dzięki temu nie ma niejasności i nieporozumień.
Inspekcja pozwala na bieżące monitorowanie i weryfikowanie przedmiotu pracy i sposobu pracy Zespołu.
Adaptacja powinna być wynikiem Inspekcji i prowadzić do niezbędnych zmian naprowadzających Zespół na właściwy tor
pracy.
Maszyna Turinga - stworzona przez Alana Turinga prosta maszyna logiczna (licząca) służąca do wykonywania algorytmów. Wszystkie współczesne komputery dają się do niej sprowadzić. Problem jest rozwiązalny na komputerze, jeśli da się zdefiniować rozwiązującą go maszynę Turinga.
Maszyna Turinga zbudowana jest z trzech głównych elementów:
Taśma
Nieskończona taśma jest odpowiednikiem współczesnej pamięci komputera. Taśma dzieli się na komórki, w których umieszczone zostały znaki przetwarzane przez maszynę Turinga. Symbole te stanowią odpowiednik danych wejściowych. Maszyna Turinga odczytuje te dane z kolejnych komórek i przetwarza na inne symbole, czyli dane wyjściowe. Wyniki obliczeń również są zapisywane w komórkach taśmy.

Można definiować różne symbole dla maszyny Turinga. Najczęściej rozważa się jedynie symbole 0, 1 oraz tzw. znak pusty - czyli zawartość komórki, która nie zawiera żadnej danej do przetworzenia. Wbrew pozorom taki prymitywny zbiór trzech symboli jest równoważny logicznie dowolnemu innemu zbiorowi
Głowica
Aby przetwarzać dane, maszyna Turinga musi je odczytywać i zapisywać na taśmę. Do tego celu przeznaczona jest właśnie głowica zapisująco-odczytująca, która odpowiada funkcjonalnie urządzeniom wejścia/wyjścia współczesnych komputerów lub układom odczytu i zapisu pamięci.
Głowica zawsze znajduje się nad jedną z komórek taśmy. Może ona odczytywać zawartość tej komórki oraz zapisywać do niej inny symbol - na tej zasadzie odbywa się przetwarzanie danych - z jednych symboli otrzymujemy inne. Oprócz odczytywania i zapisywania symboli w komórkach głowica wykonuje ruchy w prawo i w lewo do sąsiednich komórek na taśmie. W ten sposób może się ona przemieścić do dowolnie wybranej komórki taśmy.
Przed rozpoczęciem pracy maszyny Turinga głowica jest zawsze ustawiana nad komórką taśmy zawierającą pierwszy symbol do przetworzenia. W klatce taśmy po lewo jest zapisany specjalny znak, tzw. lewy ogranicznik. Jeżeli głowica znajduje się nad lewym ogranicznikiem, to nie może go zamazać ani przesunąć się na lewo od niego. Po zakończeniu danych wejściowych taśma wypełniona jest w nieskończoność specjalnymi pustymi symbolami, tzw. blank'ami.
Układ Starowania
Przetwarzaniem informacji zarządza układ sterowania głowicą. Jego współczesnym odpowiednikiem jest procesor komputera. Układ ten odczytuje za pomocą głowicy symbole z komórek taśmy oraz przesyła do głowicy symbole do zapisu w komórkach. Dodatkowo nakazuje on głowicy przemieścić się do sąsiedniej komórki w lewo lub w prawo.
Podstawą działania maszyny Turinga są stany układu sterowania. Stan układu sterowania określa jednoznacznie jaką operację wykona, jak zareaguje maszyna Turinga, gdy odczyta z taśmy określony symbol.
Zatem operacje wykonywane przez układ sterowania zależą od dwóch czynników:
Stany będziemy określać kolejnymi nazwami: q0, q1, q2, ... ,qn, gdzie q0 jest stanem początkowym, w którym znajduje się maszyna Turinga przed rozpoczęciem przetwarzania symboli na taśmie.
Instrukcją dla maszyny Turinga jest następująca piątka symboli:

S0 i qi są tzw. częścią identyfikacyjną instrukcji. Maszyna Turinga wykonuje tyle różnych instrukcji, ile zdefiniujemy części identyfikacyjnych - w programie nie może być dwóch różnych instrukcji o identycznej części identyfikacyjnej.
Sz, qj i L/P są tzw. częścią operacyjną, która określa jakie działanie podejmuje dana instrukcja. Części operacyjne różnych instrukcji mogą być takie same - oznacza to jedynie, iż instrukcje te wykonują dokładnie to samo działanie.
Przyklad instrukcji
Jeżeli odczytanym przez głowicę symbolem z taśmy będzie symbol A, a układ sterowania znajduje się w stanie q0, to głowica zamieni ten symbol na B, stan wewnętrzny nie zmieni się (pozostanie dalej q0), a głowica przesunie się do sąsiedniej komórki po prawej stronie.
Formalna Definicja
Każdy problem, który może być intuicyjnie uznany za obliczalny, jest rozwiązywalny przez maszynę Turinga.
Sformułowanie "intuicyjnie uznany za obliczalny" uniemożliwia przeprowadzenie matematycznego dowodu tej hipotezy.
Bardziej praktyczna definicja
Każdy problem, dla którego przy nieograniczonej pamięci oraz zasobach istnieje efektywny algorytm jego rozwiązywania, da się rozwiązać na maszynie Turinga
Trzecie równoważne sformułowanie
Każdy nieinteraktywny program może być zredukowany do rozwiązującej go maszyny Turinga, a ta może być wyrażona w każdym zupełnym w sensie Turinga języku programowania.
Dlatego równoważne sformułowanie tej hipotezy mówi, że każdy istniejący algorytm można wyrazić w każdym zupełnym języku programowania.
Translacja Adresów Sieciowych (Network Adress Translation, NAT) - technika przesyłania ruchu sieciowego poprzez router, która wiąże się ze zmianą źródłowych lub docelowych adresów IP, zwykle również numerów portów TCP/UDP pakietów IP podczas ich przepływu. Zmieniane są także sumy kontrolne (zarówno w pakiecie IP, jak i w segmencie TCP/UDP), aby potwierdzić wprowadzone zmiany.
Alternatywna Definicja
NAT jest procesem modyfikującym informację o adresie IP w nagłówku pakietu IP, w momencie przesyłania ruchu przez urządzenie sieciowe. W większości konfiguracji, NAT podmienia prywatne adresy wewnątrz sieci na adresy IP publiczne, udostępniane przez dostawcę usługi dostępu do internetu. Taki zabieg pozwala komputerom w sieci domowej czy firmowej współdzielić połączenie internetowe. Dodatkowo, uzyskuje się zwiększony poziom bezpieczeństwa sieci, ponieważ dostęp do sieci wewnętrznej z zewnątrz jest mocno ograniczony.
Dwa podstawowe typy NAT:
Wyróżniamy trzy rodzaje SNAT:
W momencie, gdy wraca do nas odpowiedź na ten pakiet urządzenie NAT przypisuje pakietowi odpowiedni adres lokalnego węzła. Odwzorowania między pakietami a adresami zapamietywane są w tablicy translacji NAT.
Przyklady działania SNAT`U
Wysyłanie request`u przez (Statyczny/Dynamiczny SNAT):

Otrzymanie odpowiedzi przy (Statycznym/Dynamicznym SNAT):

Otrzymanie odpowiedzi z wlączanym PAT:

Trasowanie (Routing) - to mechanizm wyznaczania trasy i przesyłania pakietów danych w intersieci, od stacji nadawczej do stacji odbiorczej.
Intersieć - to minimum dwie sieci fizyczne połączone ze sobą za pomocą routera.
Trasowaniem zajmuje się urządzenie zwane routerem: może to być zwykły komputer jak i urządzenie specjalnie dedykowane tylko do tego zadania, tzw. router sprzętowy.
Trasowanie umożliwia danym z jednej sieci lokalnej dotrzeć do innej sieci lokalnej, która może znajdować się w dowolnym miejscu na świecie. Trasa może prowadzić przez wiele sieci pośrednich, tak więc routing jest jakby spoiwem łączącym Internet w całość. Bez routowania cały ruch danych byłby ograniczony do jednej fizycznej sieci.
UWAGA
Trasowanie realizowane jest w warstwie trzeciej (sieciowej) modelu OSI. Wyznaczane trasy pakietów danych musza być jak najbardziej optymalne – czyli możliwie najszybsze, ale umożliwiające dostarczenie wszystkich pakietów.
Pakiet to jednostka informacji, której źródłem i przeznaczeniem jest warstwa Sieciowa (warstwa 3) modelu OSI. Pakiet składa się z trzech elementów:
Nagłówek i końcówka zawierają informację sterującą przeznaczoną dla warstwy 3 w stacji odbiorczej. Można powiedzieć, że dane z wyższej warstwy są otoczone (kapsułkowane) przez nagłówek i końcówkę warstwy 3.
Datagram jest jednostką informacji, której źródłem i przeznaczeniem jest warstwa Sieciowa (warstwa 3) modelu OSI, używająca bezpołączeniowej obsługi sieci. Pakiet (połączeniowa obsługa sieci) = datagram (bezpołączeniowa)
Etapy trasowania:
Tablica Routingu
Router przechowuje tzw. tablicę routingu, dzięki której wie, jak kierować ruchem. Najważniejsze informacje zawarte w tablicy to adresy sąsiednich routerów i adresy sieci docelowych.
| Aby dotrzeć do sieci | Wyślij do urządzenia o adresie |
|---|---|
| 10.1.1.0 | 10.1.2.2 |
| 10.1.2.0 | 10.1.2.2 |
| 10.1.3.0 | Bezpośrednio połączony |
Oprócz tego w tablicy mogą się też znaleźć informacje o całościowym koszcie (metryce) wysłania daną trasą pakietu (jest to pewna liczba przypisana trasie przez protokoły routingu), nazwy czy adresy interfejsów sieciowych, przez które dany pakiet jest kierowany do sieci, flagi opisujące właściwości danej ścieżki (H - ścieżka do konkretnego komputera, a nie np. do kolejnego routera, U – ścieżka jest drożna i działa bez problemów), licznik określający czas, jaki upłynął od ostatniego uaktualnienia informacji o trasie.
Pakiet danych przechodzi pomiędzy kolejnymi sieciami. Takie kolejne przejście nazywane jest przeskokiem lub hop-em. Tablica routingu zawarta w routerze lub w komputerze sieciowym zawiera właśnie przyporządkowania adresów dotyczące jednego hopu!

Pod względem sposobu wypełniania danymi tych tablic, dzielimy routing na statyczny i dynamiczny.
Statyczny - administrator ręcznie wpisuje wszystkie adresy to tablicy routingu. Najprostszą formą budowania informacji o topologii sieci są ręcznie podane przez administratora trasy definiujące routing statyczny. Przy tworzeniu takiej trasy wymagane jest jedynie podanie adresu sieci docelowej, interfejsu, przez który pakiet ma zostać wysłany oraz adresu IP następnego routera na trasie.
Zalety
Wady
Dynamiczny - routery samodzielnie zbierają informacje i aktualizują zapisy w tablicy.
Ponieważ statyczne systemy trasowania nie mogą reagować na zmiany w sieci, to generalnie nie są one przydatne do stosowania w sieciach dużych, gdzie zmiany następują praktycznie ciągle. Dlatego większość obecnie stosowanych algorytmów trasowania to algorytmy dynamiczne, dostosowujące się do zmiennych warunków występujących w sieci, na drodze analizy aktualizujących komunikatów trasowania. W wypadku, gdy aktualizujący komunikat trasowania wskazuje, że w sieci wystąpiły zmiany, oprogramowanie trasujące ponownie oblicza trasy i wysyła do routerów nowe komunikaty aktualizujące. W ślad za tym komunikaty, przenikając przez sieć, stymulują routery do uruchomienia algorytmów trasowania i zmieniają ich tablice trasowania.
Protokoły trasowania dynamicznego są wykorzystywane przez routery do pełnienia trzech podstawowych funkcji:
Podział protokołów:
Protokoły wektora odległości:
Trasowanie może być oparte na algorytmach wektora odległości (nazywanych również algorytmami Bellmana-Forda). Nazwa pochodzi stąd, iż poszczególne routery prezentowane są jako wektory zawierające dwie informacje: dystans oraz wektor wyznaczający kierunek. Dystans opisuje całkowity koszt/metrykę danej trasy i wyrażany jest za pomocą pewnej liczby, natomiast Kierunek definiowany jest poprzez adres następnego skoku.
Etapy działania protokołu:
Router nie widzi poza swojego sąsiada i informacje o innych sieciach, nieprzyłączonych do niego bezpośrednio, uzyskuje tylko dzięki nim. Nazywa się to routingiem przez plotkowanie.

Przykładowe protokoły: RIP, EBGP.
Algorytmy trasowania na podstawie stanu łącza, ogólnie określane jako protokoły "najpierw najkrótsza ścieżka" (ang. SPF shortest path first), utrzymują złożoną bazę danych opisującą topologię sieci. W odróżnieniu od protokołów wektora odległości, protokoły stanu łącza zbierają i przechowują pełną informację na temat routerów sieci, a także o sposobie ich połączenia.
W protokołach stanu łącza każdy router przechowuje kompletną bazę danych o topologii sieci z informacjami o koszcie pojedynczych ścieżek w obrębie sieci oraz o stanie połączeń. Informacje te kompletowane są poprzez rozsyłanie tzw. pakietów LSA (Link-State Advertisement) o stanie łączy.
Przykładowe protokoły: OSPF, IS-IS, IDRP
Ostatnią formą trasowania dynamicznego jest praca hybrydowa. Choć istnieją "otwarte" zrównoważone protokoły hybrydowe, ta forma trasowania jest niemal całkowicie związana z zastrzeżonym produktem jednej firmy Cisco Systems, Inc. Protokół o nazwie EIGRP (ang. Enhanced Interior Gateway Routing Protocol) został zaprojektowany z zamiarem połączenia najlepszych cech protokołów opartych na wektorze odległości i stanie łącza, przy jednoczesnym ominięciu ich ograniczeń wydajności i innych wad.
Potrzebna informacja:
System autonomiczny – grupa sieci i routerów pod wspólną administracją (korporacje, uczelnie). Routery wewnątrz systemu autonomicznego dowolnie zarządzają trasami. Każdy system autonomiczny wybiera router lub routery przeznaczone do komunikacji z innymi systemami autonomicznymi. Odpowiadają one za przekazywanie informacji o osiągalności sieci wewnątrz „swojego” systemu do innych systemów.
Routery odpowiedzialne za komunikację z innymi systemami autonomicznymi nazywane są routerami zewnętrznymi albo brzegowymi (exterior gateways), routery działające wewnątrz systemu – wewnętrznymi (interior gateways).
Zewnętrzne:
EGP(Exterior Gateway Protocol)
Inny protokoł tego typu: (E) BGP (Exterior Border Gateway Protocol)
Wewnętrzne:
Grupę protokołów używanych przez routery wewnątrz systemu autonomicznego określa się nazwą IGP (Interior Gateway Protocols)
W jaki sposób algorytmy trasowania decydują o tym, że jedna trasa jest preferowana bardziej niż inna? Rozróżnia się obecnie następujące miary trasowania:
Długość ściężki jest najczęściej używaną miarą trasowania. Niektóre protokoły trasowania zezwalają administratorowi sieci na arbitralne przypisywanie kosztów każdemu łączu sieciowemu. W takim wypadku koszt ścieżki jest sumą kosztów związanych z każdym łączem składającym się na ścieżkę. Inne protokoły trasowania natomiast używają miary hop count, rozumianej jako liczba przejść pakietu przez urządzenia intersieciowe - np. routery - od stacji nadawczej do stacji odbiorczej.
Niezawodność, w kontekście algorytmów trasowania, odnosi się do skuteczności każdego łącza (określanego liczbą przekłamanych bitów). Niektóre łącza mogą ulegać uszkodzeniom częściej od innych. Po uszkodzeniu sieci niektóre łącza można naprawić szybciej i prościej niż inne.
Opóźnienie trasowania oznacza czas potrzebny do przesłania pakietu od stacji nadawczej do stacji odbiorczej w intersieci.
Szerokość pasma odnosi się do dostępnej pojemności ruchu w określonym łączu
Obciążenie to stopień zajętości zasobu sieciowego, np. routera. Obciążenie zależy od wielu czynników, np. stopnia wykorzystania procesora czy liczby pakietów przetwarzanych w czasie jednej sekundy.
Koszt komunikacji jest ważną miarą trasowania, przede wszystkim dlatego, że niektóre firmy nie dbają o wydajność. Nawet wtedy, gdy opóźnienia są duże, przesyłają pakiety przez własne linie zamiast korzystać z sieci publicznych, za które się płaci tylko w czasie ich używania.
Ogółny Zarys
Usługi nazewnicze wykorzystywane są do dystrybuowania informacji. One tłumaczą nazwy hostów na adresy IP. Internetowym standardem jest DNS, ale w pewnych sytuacjach wykorzystywane są NIS i WINS.
DNS(ang. Domain Name System, system nazw domenowych) to system serwerów oraz protokół komunikacyjny zapewniający zamianę adresów znanych użytkownikom Internetu na adresy zrozumiałe dla urządzeń tworzących sieć komputerową. Dzięki wykorzystaniu DNS nazwa mnemoniczna, np. pl.wikipedia.org, może zostać zamieniona na odpowiadający jej adres IP, czyli 145.97.39.135.
Adresy DNS składają się z domen internetowych rozdzielonych kropkami. Dla przykładu w adresie Wikipedii org oznacza domenę funkcjonalną organizacji, wikipedia domenę należącądo fundacji Wikimedia, a pl polską domenę w sieci tej instytucji. W ten sposób możliwe jest budowanie hierarchii nazw, które porządkują Internet.
Strona Techniczna
Podstawą technicznego systemu DNS jest ogólnoświatowa sieć serwerów przechowujących informacje na temat adresów domen. Każdy wpis zawiera nazwę oraz odpowiadającą jej wartość, najczęściej adres IP. System DNS jest podstawą dla rozwiązywania nazw hostów w Internecie.
DNS to również protokół komunikacyjny opisujący sposób łączenia się klientów z serwerami DNS. Częścią specyfikacji protokołu jest również zestaw zaleceń, jak aktualizować wpisy w bazach domen internetowych. Na świecie jest wiele serwerów DNS, które odpowiadają za obsługę poszczególnych domen internetowych. Domeny mają strukturę drzewiastą, na szczycie znajduje się 13 głównych serwerów (root servers) obsługujących domeny najwyższego poziomu (TLD – top level domains).
Serwery najwyższego poziomu z reguły posiadają tylko odwołania do odpowiednich serwerów DNS odpowiedzialnych za domeny niższego rzędu, np. serwery główne (obsługujące między innymi TLD.com) wiedzą, które serwery DNS odpowiedzialne są za domenę example.com. Serwery DNS zwracają nazwę serwerów odpowiedzialnych za domeny niższego rzędu. Możliwa jest sytuacja, że serwer główny odpowiada, że dane o domenie example.com posiada serwer dns.example.com. W celu uniknięcia zapętlenia w takiej sytuacji serwer główny do odpowiedzi dołącza specjalny rekord (tak zwany glue record) zawierający także adres IP serwera niższego rzędu (w tym przypadku dns.example.com).
Wewnątrz każdej domeny można tworzyć tzw. subdomeny - stąd mówimy, że system domen jest 'hierarchiczny'. Przykładowo wewnątrz domeny .pl utworzono wiele domen:
Nazwy domen i poszczególnych komputerów składają się z pewnej liczby nazw, oddzielonych kropkami. Ostatnia z tych nazw jest domeną najwyższego poziomu. Każda z tych nazw może zawierać litery, cyfry lub znak '-'. Od niedawna w nazwach niektórych domen można używać znaków narodowych (IDN) takich jak 'ą' czy 'ż', ale większośćwspółczesnych programów nie przewiduje możliwości wykorzystania takich funkcji. Wewnątrz każdej z poddomen można tworzyć dalsze poddomeny, np. w domenie 'wikipedia.org' można utworzyć domenępl.wikipedia.org.
DNS, jako system organizacyjny, składa się z dwóch instytucji - IANA i ICANN. Nadzorująone ogólne zasady przyznawania nazw domen i adresów IP. Jednak te dwie instytucje nie sąw stanie zajmować się całym światem i dlatego cedują swoje uprawnienia na szereg lokalnych instytucji i firm.
Najważniejsze cechy DNS:
Rodzaje zapytań DNS
Zmusza serwer do znalezienia wymaganej informacji lub zwrócenia wiadomości o błędzie. Ogólną zasadą jest, że zapytania od resolwera (program, który potrafi wysyłać zapytania do serwerów DNS) do serwera są typu rekurencyjnego, czyli resolwer oczekuje podania przez serwer adresu IP poszukiwanego hosta. Wykonywanie zapytań rekurencyjnych pozwala wszystkim uczestniczącym serwerom zapamiętać odwzorowanie (ang. DNS caching), co podnosi efektywność systemu.
Wymaga od serwera jedynie podania najlepszej dostępnej mu w danej chwili odpowiedzi, przy czym nie musi on łączyć się jeszcze z innymi serwerami. Zapytania wysyłane pomiędzy serwerami są iteracyjne, przykładowo wiarygodny serwer domeny org nie musi znać adresu IP komputera www.pl.wikipedia.org, podaje więc najlepszą znaną mu w tej chwili odpowiedź, czyli adresy serwerów autorytatywnych dla domeny wikipedia.org
Odpowiedzi na zapytania
Dotyczące domeny w strefie, nad którą dany serwer ma zarząd, pochodzą one bezpośrednio z bazy danych serwera; jest to pozytywna odpowiedź zwracana do klienta, która w komunikacie DNS zawiera ustawiony bit uwierzytelniania (AA – Authoritative Answer) wskazujący, że odpowiedź została uzyskana z serwera dokonującego bezpośredniego uwierzytelnienia poszukiwanej nazwy
Dane które zwraca serwer pochodzą spoza zarządzanej przez niego strefy; odpowiedzi nieautorytatywne są buforowane poprzez serwer przez czas TTL wyrażony w sekundach, wyspecyfikowany w odpowiedzi, a następnie po upływie czasu są usuwane
Komunikaty DNS
Zapytania i odpowiedzi DNS są najczęściej transportowane w pakietach UDP. Każdy komunikat musi się zawrzeć w jednym pakiecie UDP (standardowo 512 oktetów, ale wielkość tę można zmieniać pamiętając również o ustawieniu takiej samej wielkości w MTU – Maximum Transmission Unit). W innym przypadku przesyłany jest protokołem TCP i poprzedzony dwubajtową wartością określającą długość zapytania i długość odpowiedzi (bez wliczania tych dwóch bajtów).
NAGLÓWEK - (Header)
ZAPYTANIE - (Question) do serwera nazw
ODPOWIEDŻ - (Answer) zawiera rekordy będące odpowiedzią
ZWIERZCHNOŚĆ - (Authority) wskazuje serwery zwierzchnie dla domeny
DODATKOWE - (Additional) sekcja informacji dodatkowych
| Ex. 1 | Ex. 2 | Ex. 3 |
|---|---|---|
| Ts | Ts | Ts |
Wirtualna sieć lokalna, VLAN (ang. virtual local area network) - sieć komputerowa wydzielona logicznie w ramach innej, większej sieci fizycznej.
Wirtualne sieci lokalne (Virtual Local Area Networks, VLANs) umożliwiają podział większej fizycznej sieci komputerowej na logiczne, odizolowane segmenty. Kształtowanie przepływu ruchu między sieciami VLAN odbywa się w warstwie 3. modelu OSI.
Virtual LAN dzieli fizyczne łącza na logiczne segmenty, ale sposób zaprojektowania wirtualnej sieci lokalnej zależy od administratora, a raczej przyjętych w organizacji założeń w zakresie kształtowania przepływu ruchu oraz wymaganego poziomu bezpieczeństwa. W ten sposób na jednym fizycznym przełączniku można utworzyć dwie (lub więcej) odizolowane od siebie sieci lokalne.
Tylko urządzenia przynależące do tej samej sieci VLAN mogą komunikować się ze sobą, każda sieć VLAN tworzy bowiem niezależną domenę rozgłoszeniową. Przełączniki przekazują ruch transmisji pojedynczej (unicast), grupowej (multicast) i rozgłoszeniowej (broadcast) tylko w ramach jednego segmentu sieci LAN. Poza izolacją segmentów sieci podejście to pozwala też ograniczyć zalewanie portów przełącznika rozgłoszeniami z protokołów ARP i DHCP, które nigdy nie przekraczają granic sieci VLAN.
Mechanizm routingu między VLAN, choć wymaga zastosowania dodatkowych urządzeń, pozwala kształtować przepływy ruchu między poszczególnymi segmentami sieci komputerowej. Mowa tutaj o kontroli dostępu, filtrowaniu ruchu na zaporze sieciowej czy zapewnianiu jakości usług (QoS).
Praktyczne zastosowanie
Sieć VLAN może służyć do segmentacji według struktury organizacyjnej. W instytucjach publicznych komputery pracowników działów finansowych i HR nie powinny komunikować się ze względów bezpieczeństwa z urządzeniami pozostałego personelu biurowego. Z kolei w firmie produkcyjnej technologia VLAN może odizolować ruch sieci komputerowej udostępnianej pracownikom biurowym od sieci komputerowej wykorzystywanej w wydziałach produkcyjnych na potrzeby zbierania danych i sterowania maszynami.
Inne praktyczne zastosowanie sieci VLAN to segmentacja ruchu sieciowego ze względu na jego typ. Podejście to sprawdzi się w każdej instytucji, nawet gdy nie ma jawnej potrzeby izolowania ruchu według struktury organizacyjnej. Oddzielne VLAN stosuje się dla serwerów, punktów końcowych (stacje robocze, laptopy), drukarek, urządzeń mobilnych (strategia BYOD), telefonów VoIP, sieci Wi-Fi dla gości, sieci zarządzania (management) czy strefy DMZ.
Protokół IEEE 802.1Q
VLAN to wydzielona logicznie sieć komputerowa warstwy 2. (łącza danych) modelu OSI. Grupuje logicznie porty jednego lub wielu przełączników sieciowych niezależnie od ich położenia. Podstawowym, powszechnie stosowanym protokołem oznaczania ramek i trunkingu jest IEEE 802.1Q. Protokół ten, nazywany także Dot1q, stał się branżowym standardem definiującym sposób obsługi VLAN w sieciach Ethernet.
Działanie sieci VLAN bazuje na dodawaniu 4-bajtowych znaczników (tagów) wewnątrz nagłówka ramek Ethernet, które pozwalają urządzeniom sieciowym sterować przepływem ruchu. Znacznik ten, o nazwie 802.1Q Header, umieszczany jest między polem adresu źródłowego (Source MAC) a polem wskazującym na typ ramki/długość (EtherType/Size). Pierwsze dwa bajty tego znacznika (Tag Protocol ID, TPID) mają stałą wartość 0x8100 i umożliwiają przełącznikowi odróżnienie znakowanej ramki 802.1Q od ramki nieznakowanej, która w tym miejscu miałaby pole EtherType/Size. Pozostałe dwa bajty (Tag Control Information, TCI) zawierają informacje służące do oznaczenia priorytetu ramki (definiowany w standardzie 802.1p), standardu sieci LAN (Ethernet lub Token Ring) oraz numeru wirtualnej sieci (VLAN ID), do której przynależy dana ramka. Wspomniane pole VLAN ID, stanowiące identyfikator sieci wirtualnej, ma długość 12 bitów i pozwala skutecznie przypisać ramkę do właściwego segmentu VLAN. W rezultacie na przełączniku można zdefiniować maksymalnie do 4096 sieci VLAN, z czego dwie są zarezerwowane do innych celów, a VLAN 1 pełni funkcję sieci natywnej.
W tym miejscu warto też wspomnieć o innym protokole znakowania i trunkingu. InterSwitch Link (ISL) to własnościowy protokół Cisco używany w przełącznikach tej firmy. Oryginalna ramka Ethernet pozostaje niezmieniona, jest bowiem kapsułkowana w ramce ISL, której nagłówek zawiera znacznik VLAN ID. Protokół ISL został uznany za przestarzały, nie powinien być dalej używany. Co więcej, nie jest wspierany przez najnowsze przełączniki Cisco.
Punkty końcowe mogą komunikować się ze sobą w ramach jednej sieci VLAN. Przekazywanie ruchu sieciowego między sieciami VLAN wymaga zastosowania routera lub przełącznika działającego w warstwie 3. (sieci) modelu OSI.
| Ex. 1 | Ex. 2 | Ex. 3 |
|---|---|---|
| Ts | Ts | Ts |
Są 2 rodzaje optymalizacji:
Pierwsza z podanych klasyfikacji wyróżnia optymalizację statyczną i optymalizację dynamiczną. Optymalizacja statyczna polega na znalezieniu „najlepszego” planu wykonania zapytania, przed rozpoczęciem wykonywania zapytania. W trakcie realizacji zapytania plan wykonania zapytania nie ulega już zmianie – stąd nazwa optymalizacja statyczna. Optymalizacja dynamiczna polega na znalezieniu „najlepszego” planu wykonania zapytania, przed rozpoczęciem wykonywania zapytania, ale później, w trakcie wykonywania zapytania jego plan wykonania może ulęgać zmianie. Aktualnie, komercyjne systemy baz danych zapewniają jedynie optymalizację statyczna, choć efektywność takiej optymalizacji jest najczęściej niższa aniżeli efektywność optymalizacji dynamicznej. Optymalizacja dynamiczna jest jednak znacznie bardziej kosztowna. Druga z podanych klasyfikacji wyróżnia optymalizację pojedynczego zapytania oraz jednoczesną optymalizację wielu zapytań. W przypadku optymalizacji pojedynczego zapytania, optymalizacji podlega tylko jedno zapytanie. W przypadku jednoczesnej optymalizacji wielu zapytań, częściowe wyniki wykonania jednego zapytania mogą być wykorzystane przez wiele innych zapytań, co prowadzi do minimalizacji czasu wykonania zbioru zapytań. W chwili obecnej systemy komercyjnych baz danych zapewniają jedynie optymalizację pojedynczego zapytania.
Ogółny proces optymalizacji zapytań:
W wyniku zastowania transformacji algebraicznych uzyskujemy zbiór najlepszych planów wykonania pojedynczych bloków zapytania. Pozostaje jeszcze problem połączenia bloków, w szczególności, problem zdefiniowania porządku wykonywania operacji połączenia. Wybór kolejności wykonywania operacji połączenia, tzn. wybór uszeregowania operacji połączenia, kończy proces optymalizacji zapytania.
Dekompozycja
Pierwszą fazą przetwarzania zapytania jest dekompozycja zapytania. Celem procesu dekompozycji zapytania jest transformacja zapytania wyrażonego w języku wysokiego poziomu na wyrażenie algebry relacji i weryfikacja syntaktycznej i semantycznej poprawności zapytania. Proces dekompozycji składa się z następujących etapów:
Analiza zapytania
Celem etapu analizy jest analiza syntaktyczna poprawności zapytania. W skład tej analizy wchodzi weryfikacja poprawności atrybutów i relacji (czy w bazie danych występują wyspecyfikowane w zapytaniu relacje i atrybuty, czy zapytanie poprawnie specyfikuje typy danych).
Następnie, zapytanie wyrażone w języku SQL jest transformowane do postaci reprezentacji wewnętrznej (wyrażenia algebry relacji, które można zapisać w postaci drzewa, jak na przykładzie poniżej), bardziej adekwatnej do procesu dalszego przetwarzania zapytania.
Select *
From Employee E, Department D
Where E. deptId = D. DeptId
And E.position = 'manager' and D.location = ‘London';

Normalizacja
Kolejnym etapem fazy dekompozycji jest normalizacja zapytania. Celem etapu normalizacji zapytania jest przekształcenie wewnętrznej reprezentacji zapytania do znormalizowanej postaci koniunkcyjnej lub dysjunkcyjnej. W fazie tej sekwencja predykatów selekcji jest przekształcana do normalnej postaci koniunkcyjnej lub normalnej postaci dysjunkcyjnej. Postać dysjunkcyjna jest, najczęściej, mniej efektywna, gdyż wymaga niezależnego wartościowania poszczególnych składowych wyrażenia. Przykłady postaci koniunkcyjnej i dysjunkcyjnej wyrażenia zapytania:

Analiza semantyczna zapytania(1)
Kolejnym, ważnym, etapem dekompozycji zapytania jest etap analizy semantycznej
zapytania. Celem analizy semantycznej zapytania jest odrzucenie niepoprawnie
sformułowanych lub sprzecznych zapytań. Zapytanie jest niepoprawnie sformułowane,
jeżeli jego elementy składowe nie prowadzą do generacji wyniku. Zapytanie jest
sprzeczne, jeżeli jego predykaty nie mogą być spełnione przez żadną krotkę w bazie
danych. Przykładem klauzuli, która jest sprzeczna jest wyrażenie:
position = ‘manager’
and position = ‘assistant’.
Zakładając, że baza danych jest w 1NF, nie istnieje w bazie danych żadna krotka, któraby
jednocześnie spełniała oba predykaty. Wartość sprzecznej klauzuli interpretujemy jako
wartość FALSE. W związku z tym, wyrażenie zawierające sprzeczna klauzulę można
uprościć.
Przykładowo, wyrażenie
(position = ‘manager’ and position = ‘assistant’) or salary > 1000;
ze względu na sprzeczność klauzuli : „position = ‘manager’ and position = ‘assistant’”
można uprościć do postaci „salary > 1000”
Analiza semantyczna zapytania(2)
Niestety, algorytmy oceny poprawności semantycznej zapytań istnieją tylko dla pewnej klasy zapytań, nie zawierających dysjunkcji i negacji. W jaki sposób rozwiązywany jest problem zapytań niepoprawnie sformułowanych oraz zapytań sprzecznych? Rozwiązanie problemu zapytań niepoprawnie sformułowanych opiera się na konstrukcji tak zwanego grafu połączenia relacji. W grafie tym, wierzchołki odpowiadają relacjom, natomiast luki odpowiadają operacjom połączenia wyspecyfikowanych w zapytaniu. Dodatkowo, graf połączenia relacji zawiera wierzchołek reprezentujący wynik zapytania. Jeżeli graf połączenia relacji nie jest spójny, to zapytanie jest niepoprawnie sformułowane.
Rozwiązanie problemu zapytań niepoprawnie sformułowanych opiera się na konstrukcji tak zwanego grafu połączeń atrybutów.
Przykłady tworzenia tych grafów (str: 10-12)
Kolejnym etapem fazy dekompozycji jest upraszczanie zapytań. Celem tego etapu jest identyfikacja wyrażeń redundantnych, eliminacja wspólnych podwyrażeń, i transformacja zapytania do równoważnej postaci, ułatwiającej dalsze przekształcanie zapytania. Transformacja zapytania do postaci równoważnej polega na zastosowaniu znanych reguł algebry relacji.
Kolejnym etapem fazy dekompozycji jest etap restrukturyzacji, czy tez transformacji zapytania. Zanim jednak przejdziemy do przedstawienia podstawowych reguł transformacji, wróćmy na chwilę do problemu konstrukcji podstawowych bloków zapytania. Tradycyjne podejście do konstrukcji bloków zapytania opera się na zastosowaniu transformacji algebraicznych, jednakże, zbiór stosowanych transformacji różni się zasadniczo dla różnych systemów komercyjnych.
Co więcej, nie wszystkie transformacje gwarantują minimalizację czasu wykonania danego bloku. W ostatnim czasie, coraz częściej, konstrukcja bloków opiera się na optymalizacji kosztowej, w której, dla każdego bloku, konstruujemy możliwe plany wykonania danego bloku i szacujemy koszt i rozmiar wykonania każdego planu. Ostatecznie wybierany jest plan wykonania o najniższym szacowanym koszcie. Do zakończenia procesu optymalizacji pozostaje jeszcze znalezienie najlepszego drzewa operacji połączenia, łączącego wyniki wykonania bloków zapytania. Tradycyjne podejście do problemu znajdowania najlepszego drzewa operacji połączenia (nazywane często podejściem w stylu systemu R) polega na zastosowaniu algorytmu programowania dynamicznego.
Każdy plan wykonania zapytania jest częściowo uporządkowanym zbiorem operacji. W skład tego zbioru operacji wchodzą: operacja skanowania, selekcji, projekcji, połączenia, produktu kartezjańskiego, operacje grupowania i agregacji. Problem znalezienia najlepszego planu wykonania zapytania obejmuje, z jednej strony, określenie kolejności wykonania operacji wchodzących w skład zapytania, z drugiej, określenia metody wykonania poszczególnych operacji. Przykładowo, mamy dwie metody dostępu do relacji: bezpośrednie skanowanie (odczyt) relacji lub dostęp do relacji poprzez skanowanie indeksu założonego na relacji. Podstawowa reguła optymalizacji mówi, że wszystkie operacje unarne (projekcja i selekcja) należy przesunąć w dół drzewa zapytania, tzn. wykonywać w pierwszej kolejności. Operacje te charakteryzują się silną własnością redukcji (filtrowania) przetwarzanych danych. Redukując rozmiar przetwarzanych danych, operacje unarne prowadzą do poprawy efektywności wykonywania operacji binarnych. Dlatego, operacje binarne (połączenie, produkt kartezjański) należy przesunąć w kierunku korzenia drzewa zapytania. Dla operacji binarnych, np. połączenia, poza określeniem kolejności ich wykonywania, należy wybrać również metodę ich wykonania (dla połączenia - nested loop, sort-merge, hash-join). Najczęściej, na końcu planu wykonania zapytania znajdują się operacje grupowania i agregacji.
Reguły transformacji oparte na algebrze relacji (Strony: 17-20)
Ważne
Zapytania zawierające skorelowane podzapytania zagnieżdżone są kosztowne w realizacji, gdyż wymagają sprawdzenia, dla każdej krotki zapytania zewnętrznego, czy spełniony jest dla tej krotki warunek podzapytania skorelowanego. Klasyczna metoda transformacji takich zapytań polega na przepisaniu zapytania w taki sposób, aby usunąć zagnieżdżenie (ang. unnesting). Usunięcie zagnieżdżenia polega na zastąpieniu zagnieżdżenia operacją połączenia.
Przykłady transformacji zagnieżdzionych zapytań (Strony: 21-26)
Zagadnienie optymalizacji jest zagadnieniem trudnym i istnieje bardzo wiele, specyficznych, reguł transformacji dla różnych typów zapytań. Co więcej, nie zawsze jest możliwe przetransformowanie zapytań w taki sposób, aby nie zawierało podzapytań (szczególnie dla podzapytań skorelowanych). W szczególnych przypadkach, gdy czas realizacji zapytania jest nieakceptowalny, można zastosować technikę redukcji rozmiarów relacji uczestniczących w zapytaniu opartą o sekwencję operacji półpołączenia. Technika ta jest wykorzystywana do optymalizacji zapytań rozproszonych w systemach rozproszonych baz danych.
Uwierzytelnianie (ang. authentication) - roces polegający na potwierdzeniu zadeklarowanej tożsamości podmiotu biorącego udział w procesie komunikacji. Celem uwierzytelniania jest uzyskanie określonego poziomu pewności, że dany podmiot jest w rzeczywistości tym, za który się podaje.
W systemach informatycznych stosuje się następujące rodzaje uwierzytelniania:



Klasyczne uwierzytelnianie użytkownika
W przypadku wielu współczesnych środowisk informatycznych, systemów operacyjnych lub systemów zarządzania bazami danych, funkcjonuje klasyczny mechanizm uwierzytelniania poprzez hasło. Proces uwierzytelniania rozpoczyna klient żądając zarejestrowania w systemie (login). Serwer pyta o identyfikator (nazwę) użytkownika, a następnie o hasło i decyduje o dopuszczeniu do sieci. W większości przypadków nazwa użytkownika i hasło są przesyłane tekstem jawnym, co stanowić może kolejny problem zapewnienia poufności, jaką właśnie mamy osiągnąć stosując opisywany mechanizm. Stąd też takie klasyczne podejście nadaje się do wykorzystania jedynie w ograniczonej liczbie przypadków, kiedy np. mamy uzasadnioną skądinąd pewność wykluczenia możliwości podsłuchu danych uwierzytelniających.
Hasła nie są najefektywniejszą, ani najbezpieczniejszą formą weryfikacji tożsamości użytkownika, z następujących powodów:
Zdalne potwierdzanie tożsamości
W środowisku sieci TCP/IP wypracowano mechanizm prostego potwierdzania tożsamości użytkownika, który żąda zdalnego uwierzytelniania. W tym celu powstał standard RFC 1413 opisujący usługę o nazwie identd. Niezależnie od jej aktualnej przydatności i powszechności warto zdawać sobie sprawę z istoty jej działania, którą łatwo opisać w następujący sposób:

Należy też zdawać sobie sprawę z potencjalnych zagrożeń jakie niesie udostępnianie przez usługę ident informacji o przynależności procesów dokonujących komunikacji sieciowej (nie tylko klientów). W standardzie RFC 1413 oraz w praktycznych implementacjach nie realizuje się bowiem uwierzytelniania podmiotu żądającego informacji z tej usługi, może ona być zatem również nadużyta przez potencjalnego włamywacza.
Procedury uwierzytelniania jednokrotnego są częściowym rozwiązaniem problemu ochrony danych uwierzytelniających przed złamaniem w systemie wielozasobowym, np. sieci komputerowej z wieloma serwerami.
Ideą procedury uwierzytelniania jednokrotnego jest minimalizacja ilości wystąpień danych uwierzytelniających w systemie - hasło powinno być podawana jak najrzadziej. Zgodnie z tą zasadą, jeśli jeden z komponentów systemu (np. system operacyjny) dokonał pomyślnie uwierzytelniania użytkownika, pozostałe komponenty (np. inne systemy lub zarządcy zasobów) ufać będą tej operacji i nie będą samodzielnie wymagać podawania ponownie danych uwierzytelniających. Przy tym jest możliwe teoretycznie, że wszystkie komponenty samodzielnie korzystają z odmiennych mechanizmów uwierzytelniana. Wówczas, dodatkowo po pierwszorazowym uwierzytelnieniu użytkownika, system może oddelegować specjalny moduł do przechowywania odrębnych danych uwierzytelniających użytkownika i poświadczania w przyszłości jego tożsamości wobec innych komponentów systemu.
chemat SSO przedstawia poniższy rysunek. W przedstawionej na rysunku sytuacji tylko jeden serwer dokonuje uwierzytelniania klienta, reszta ufa uwierzytelnianiu dokonanemu przez ten serwer.

Istota wykorzystania haseł jednorazowych wynika zamiaru ochrony ich przed przechwyceniem i nieautoryzowanym wykorzystanie, w przyszłości. Jednak nie polega na zapewnieniu ich poufności w transmisji lecz na uczynieniu ich de facto bezwartościowymi po przechwyceniu. Opiera się na, jak sama nazwa wskazuje, tylko użyciu danej postaci hasła tylko raz. Hasła jednorazowe mają przy każdym kolejnym uwierzytelnieniu inną postać. Raz przechwycone hasło jednorazowe nie jest przydatne, bowiem przy kolejnym uwierzytelnieniu będzie obowiązywać już inne. Komunikacja między podmiotami procesu uwierzytelniania może być zatem jawna. Stosujące takie hasła procedury uwierzytelniania muszą jedynie oferować brak możliwości odgadnięcia na podstawie jednego z haseł, hasła następnego.
Hasła jednorazowe generowane są przy pomocy listy haseł, synchronizacji czasu lub metody zawołanie-odzew. Dostępne są najczęściej w następujących postaciach: listy papierowe, listy-zdrapki, tokeny programowe i tokeny sprzętowe.
Lista haseł
Listy haseł to najprostsza i najtańsza metoda identyfikacji metodą haseł jednorazowych. Użytkownik otrzymuje listę zawierająca ponumerowane hasła. Ta sama lista zostaje zapisana w bazie systemu identyfikującego. W trakcie logowania użytkownik podaje swój identyfikator, a system prosi o podanie hasła z odpowiednim numerem. Klient za każdym razem posługuje się kolejnym niewykorzystanym hasłem z listy.

Metoda synchronizacji czaswoej
W metodzie z synchronizacją czasu (time synchronization) klient generuje unikalny kod w funkcji pewnego parametru X użytkownika (identyfikatora, kodu pin, hasła, numeru seryjnego karty identyfikacyjnej) oraz bieżącego czasu. Serwer następnie weryfikuje otrzymany od klienta kod korzystając z identycznej funkcji (z odpowiednią tolerancją czasu).

Metoda "Zawołanie-Odzew"
Natomiast w metodzie zawołanie-odzew (challenge-response) serwer pyta o nazwę użytkownika, a następnie przesyła unikalny ciąg („zawołanie"). Klient koduje otrzymany ciąg (np. swoim hasłem lub innym tajnym parametrem pełniącym rolę klucza) i odsyła jako „odzew". Serwer posługując się identycznym kluczem weryfikuje poprawność odzewu.

Metoda Tokenów
Tokeny programowe to specjalne programy generujące hasła. W zależności od implementacji program na podstawie kwantu czasu lub zawołania serwera generuje hasło jednorazowe, które weryfikuje serwer.
Token sprzętowy jest małym przenośnym urządzeniem spełniającym wszystkie funkcje tokenu programowego.
Pewną ciekawostką zyskującą na popularności jest wykorzystanie telefonu komórkowego w uwierzytelnianiu za pomocą haseł jednorazowych. Cały proces polega przesłaniu hasła jednorazowego z serwera na telefon w postaci wiadomości SMS. W tym przypadku rola telefonu jako swoistego tokena sprowadza się tylko do medium odbierającego i wyświetlającego dane.
Inne mechanizmy uwierzytelniania
Do uwierzytelniania użytkowników można wykorzystać również przedmioty, których posiadaniem musi się wykazać uwierzytelniany. Mogą to być np. karty magnetyczne, karty elektroniczne czy tokeny USB. Ponadto, w przypadku ludzi, można posłużyć się również cechami osobowymi wynikającymi z odmienności parametrów niektórych naturalnych składników organizmu (uwierzytelnianie biometryczne), takich jak m.in.:
Autoryzacja i kontrola dostępu zaczyna się tam, gdzie kończy się uwierzytelnianie. Kiedy podmiot zabezpieczeń SP (Security Principal) podejmuje próbę uzyskania dostępu do chronionego obiektu lub usługi, proces autoryzacji przejmuje jego tożsamość i używa jej do określenia jego uprawnień.
Zadania autoryzacji i kontroli dostępu legalnych użytkowników należą do podstawowych funkcji systemów operacyjnych czy systemów zarządzania bazą danych oraz środowisk przetwarzania rozproszonego. W większości przypadków te funkcje są realizowane podobnie.
Jeżeli SP próbuje uzyskać dostęp (np. do pliku na serwerze WWW), usługa autoryzacji kwerenduje bazę danych, aby określić, jakie uprawnienia związane z tym plikiem ma SP. System kontroli dostępu jest programem lub procesem egzekwującym uprawnienia i przywileje. Generalnie, część autoryzacyjna systemu określa, że SP może tylko czytać dany plik, a system kontroli dostępu w rzeczywistości zapewnia, że nie może tego pliku zmodyfikować.
Modele kontroli dostępu opisują ogólne metody używane w poszczególnych domenach bezpieczeństwa do kontroli dostępu na styku SP i żądanej usługi czy obiektu.
Główna różnica między modelem dostępu RBAC a DAC polega na tym, że grupy DAC mają na ogół określać ogólną przynależność (np. zespół działu kadr), podczas gdy wyznacznikiem RBAC są działania (np. wykonywane przez pracownika działu kadr, działu płac itp.).
Wiele modeli RBAC (w tym sporo zaimplementowanych jako warstwa nad systemami DAC) dopuszcza tylko szczególne uprawnienia w trakcie wykonywania przez SP koniecznych działań. I tak np. w tym modelu pracownik zajmujący się wypłatami ma dostęp do bazy danych płac tylko wtedy, gdy korzysta z aplikacji płacowej.
W domenie bezpieczeństwa opartej na DAC pracownik działu płac będzie miał prawdopodobnie uprawnienia do zapisów oraz odczytu całej bazy danych, i te uprawnienia będą stałe oraz niezależne od aplikacji.
Systemy RBAC są dużo bardziej bezpieczne. Preferuje je większość ekspertów ds. bezpieczeństwa, ale również wymagają znacząco większego wysiłku po stronie administrowania, podejmowania decyzji o uprawnieniach, określania delegacji ról. W codziennym użytkowaniu RBAC wymaga większej automatyzacji i stosowania globalnych praktyk zarządzania.
W praktyce rzadko można spotkać domenę bezpieczeństwa, gdzie zastosowano tylko jeden model kontroli dostępu. System operacyjny Windows jest zbudowany wokół DAC, ale już w systemie Vista Microsoft dodał MAC (stosując obowiązkową kontrolę integralności), a RBAC jest dostępny na poziomie sieciowym w Active Directory. Wiele domen opartych na DAC i RBAC umożliwia także klasyfikowanie (etykietowanie) danych, podobnie jak systemy oparte na MAC, co pomaga ustalić właściwe uprawnienia i inne zabezpieczenia, które mają być stosowane na kolejnym poziomie ochrony ważnych danych.
Aby zapewnić odpowiedni poziom bezpieczeństwa, niezbędne jest rejestrowanie pomyślnych lub podejmowanych prób dostępu, a także działań po uzyskaniu dostępu. Rozliczanie jest zazwyczaj uważane za bardziej ogólną metodę rejestrowania niż audyt. System rozliczeniowy może rejestrować tylko pojedyncze pomyślne logowania (na sesję), liczbę przesłanych danych lub całkowity czas aktywności sesji. Z audytem wiąże się dużo bardziej szczegółowy poziom kontroli, pozwalający śledzić każdą wykonywaną przez SP akcję (lub próbę wykonania) - przeglądane lub modyfikowane pliki i foldery - oraz rejestrować czas wydarzenia.
Audyt i system rozliczania dodatkowo komplikują systemy współdzielone, tożsamości i hasła. Silny system AAA wymaga unikatowych tożsamości, aby każda indywidualna akcja mogła zostać zarejestrowana oddzielnie. Poziom rozliczalności i audytu może być ustawiony przez administratora, aczkolwiek zależy częściowo od systemu AAA i używanych protokołów. Dobry system rozliczania i audytu śledzi każdą akcję wykonywaną przez każdego SP - od tworzenia obiektu aż do jego usunięcia (włączając w to zdarzenia logowania i zmiany w dzienniku zdarzeń audytu). Więcej o tym tutaj (Strony 2-5)
Alfabet
Alfabetem nazywamy dowolny niepusty zbiór skooczony. Elementy alfabetu nazywami symbolami.
Słowa
Słowem
I Wyrażenia regularne
Def
Niech będzie dany zbiór Π = { ∅, λ ,+,· ,* ,( ,) } oraz alfabet Σ, przy czym Σ ∩ Π = ∅.
Wyrażeniem regularnym nad alfabetem Σ nazywamy każde słowo A ∊ (Σ, ∏)* spełniające jeden z poniższych warunków:
Rodzinę wyrażeo regularnych nad alfabetem Σ oznaczamy przez WR(Σ)
(lub WR jeśli nie będzie wątpliwości
dotyczących alfabetu)
II Języki regularne
Def
Niech będzie dany alfabet Σ oraz rodzina wyrażeń regularnych WR zdefiniowanych nad tym alfabetem. Każdemu wyrażeniu regularnemu A∊WR przyporządkowujemy język L(A) za pomocą definicji rekurencyjnej ze względu na budowę wyrażenia regularnego A:
Mówimy, że język L(A) jest językiem generowanym przez wyrażenie regularne A, natomiast o słowach należących do języka L(A) mówimy, że są generowane przez wyrażenie regularne A.
Def.
Językiem regularnym nazywamy każdy język formalny L nad danym alfabetem, dla którego istnieje wyrażenie regularne A takie, że: L=L(A) . Klasę języków regularnych oznaczamy przez JR.
Każdy język regularny może byd generowany przez wiele wyrażeo regularnych. Def. Mówimy, że wyrażenia regularne A i B są równoważne, gdy generują ten sam język, tzn
AUTOMAT SKOŃCZONY Rabina-Scotta
Automatem skończonym (typu Nas-labmda) nazywamy uporządkowaną piątkę
Język L złożony ze wszystkich słów akceptowanych przez automat skooczony M nazywamy generowanym przez automat M i oznaczamy przez L(M)
Gdzie:
Zbiór wszystkich języków generowanych przez automaty skończone oznaczamy symbolem ZJNAS-λ.
Przykład automatu skończonego:

Automatem skończonym type DAS nazywamy uporządkowaną piątke:
Język Lzłożony ze wszystkich słów akceptowanych przez automat M typu DAS nazywamy generowanym przez automat Mi oznaczamy przez L(M)
Zbiór wszystkich języków generowanych przez automaty typu DAS oznaczamy symbolem ZJDAS.
TW. 3
Jeżeli
jest automatem typu DAS, to generuje on język L wtedy i tylko wtedy, gdy automat
generuje język L`.
Przykład automatu typu DAS:

Ważne Tw. Zbiory języków generowanych przez automaty typu DAS i NAS-λ są sobie równe:
Def Gramatyką bezkontekstową nazywamy uporządkowaną czwórkę:
Def Językiem generowanym przez gramatykę G, nazywamy zbiór
Słowo A należy do języka L opisanego przez daną gramatykę G, jeśli istnieje ciąg produkcji prowadzący od symbolu zmiennej początkowej S do danego słowa. Mówimy wówczas, że słowo A jest wyprowadzone w gramatyce G.
Def
Językiem Bezkontekstowym nazywamy język, dla którego istnieje gramatyka bezkontekstowa generująca ten język.Zbiór języków generowanych przez gramatyki bezkontekstowe oznaczamy przez ZJB.
Def
Automatem ze Stosem(AZS) nazywamy uporządkowaną siódemkę:
Opisem chwilowym automatu M nazywamy każdą trójkę (S,A,B), gdzie:
Przykładowy auyomat ze Stosem:

Tw. 17
Zbiór języków akceptowanych przez automaty ze stosem jest równy zbiorowi języków bezkontekstowych.
Maszyny Turinga
Def. Maszyną Turinga (MT) nazywamy uporządkowany układ:
Def
Język L złożony ze wszystkich słów akceptowanych przez maszyne Turinga M nazywamy językiem generowanym przez maszynę M i oznaczamy przez L(M):
Zbiór wszystkich języków generowanych przez maszyny Turinga oznaczamy symbolem ZJMT i nazywamy rekursywnie przeliczalnymi.
Maszyne Turinga można przedstawić m in. za pomocą:
Przykład Maszyny Turinga

Przykład MT akceptującej słowa i MT obliczającej:

| MT | Języki |
|---|---|
| Maszyny Turinga Niedeterministyczne maszyny Turinga Wielotaśmowe maszyny Turinga Uniwersalna maszyna Turinga |
ZJRP zbiór języków rekursywnie przeliczalnych (rekurencyjnie przeliczalnych) |
| Właściwe MT - maszyny Turinga zatrzymująca się dla każdego słowa po skończonej ilości ruchów |
ZJRK Zbiór języków rekursywnych (rekurencyjnych) |
|
MT (automaty) liniowo ograniczone – maszyny Turinga w których <,> є Γ i głowica przesuwa się tylko między symbolami < i > wyznaczającymi początek i koniec słowa. |
ZJK Zbiór języków kontekstowych. |
Istnieje język formalny, który nie jest rekursywnie przeliczalnym, tzn. nie jest akceptowany przez żadną MT.